Every day a Leetcode
题目来源:300. 最长递增子序列
解法1:递归
枚举 nums[i] 作为最长递增子序列的末尾元素,那么需要枚举 nums[j] 作为最长递增子序列的倒数第二个元素,其中 j<i 并且 nums[j]<nums[i]。
问题转化为更小的子问题:求以 nums[j] 为末尾的最长递增子序列,可以用递归来求解
代码:
// 递归
class Solution
{
public:
int lengthOfLIS(vector<int> &nums)
{
// 特判
if (nums.size() == 1)
return 1;
int n = nums.size();
function<int(int)> dfs = [&](int i)
{
int res = 0;
for (int j = 0; j < i; j++)
if (nums[j] < nums[i])
res = max(res, dfs(j));
return res + 1;
};
int ans = 0;
for (int i = 0; i < n; i++)
ans = max(ans, dfs(i));
return ans;
}
};
结果:
复杂度分析:
时间复杂度:O(n2),其中 n 是数组 nums 的元素个数。
空间复杂度:O(n),其中 n 是数组 nums 的元素个数。
解法2:动态规划
将
代码:
// 动态规划
class Solution
{
public:
int lengthOfLIS(vector<int> &nums)
{
// 特判
if (nums.size() == 1)
return 1;
int n = nums.size(), maxLength = 0;
// 状态数组,并初始化
vector<int> dp(n, 1);
// 状态转移
for (int i = 0; i < n; i++)
for (int j = 0; j < i; j++)
{
if (nums[j] < nums[i])
dp[i] = max(dp[i], dp[j] + 1); // 状态转移方程
maxLength = max(maxLength, dp[i]);
}
return maxLength;
}
};
结果:
复杂度分析:
时间复杂度:O(n2),其中 n 是数组 nums 的元素个数。
空间复杂度:O(n),其中 n 是数组 nums 的元素个数。
解法3:贪心 + 二分查找
遍历数组 nums:
最后 g 就是最长递增子序列。
对应到代码上,就是把 lower_bound 改成 upper_bound。
代码:
// 贪心 + 二分查找
class Solution
{
public:
int lengthOfLIS(vector<int> &nums)
{
// 特判
if (nums.size() == 1)
return 1;
int n = nums.size();
vector<int> g;
for (int i = 0; i < n; i++)
{
int j = lower_bound(g.begin(), g.end(), nums[i]) - g.begin();
if (j == g.size())
g.push_back(nums[i]);
else
g[j] = nums[i];
}
return g.size();
}
};
结果:
复杂度分析:
时间复杂度:O(nlogn),其中 n 是数组 nums 的元素个数。
空间复杂度:O(n),其中 n 是数组 nums 的元素个数。