一、题目
给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。
子序列 是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/longest-increasing-subsequence/description/
二、C++解法
我的思路及代码
动态规划
定义 dp 数组为以当前字符结尾的最长递增子序列,dp的初始状态为 1,因为至少都是以自己结尾,所以至少都有 1 个字符。dp[i] 的取值是由 当nums[i] 大于 num[j] 时,dp[i] = max(dp[i],dp[j]+1),加一是因为要算上自己嘛。最后找到dp中最大的数即可。
class Solution {
public:
int max(int a,int b){
return a>b?a:b;
}
int lengthOfLIS(vector<int>& nums) {
int dp[nums.size()];
int temp=0;
int ans=0;
for(int i=0;i<nums.size();i++)
dp[i] = 1;
for(int i=0;i<nums.size();i++){
for(int j=0;j<i;j++){
if(nums[i]>nums[j])
dp[i] = max(dp[i],dp[j]+1);
}
}
for(int num:dp)
ans = max(num,ans);
return ans;
}
};
- 时间复杂度:O(n2),其中 n 为数组 nums 的长度。动态规划的状态数为 n,计算状态 dp[i] 时,需要 O(n) 的时间遍历 dp[0…i−1] 的所有状态,所以总时间复杂度为 O(n2)
- 空间复杂度:O(n),需要额外使用长度为 n 的 dp 数组。
官方参考代码
贪心 + 二分查找
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
int len = 1, n = (int)nums.size();
if (n == 0) {
return 0;
}
vector<int> d(n + 1, 0);
d[len] = nums[0];
for (int i = 1; i < n; ++i) {
if (nums[i] > d[len]) {
d[++len] = nums[i];
} else {
int l = 1, r = len, pos = 0; // 如果找不到说明所有的数都比 nums[i] 大,此时要更新 d[1],所以这里将 pos 设为 0
while (l <= r) {
int mid = (l + r) >> 1;
if (d[mid] < nums[i]) {
pos = mid;
l = mid + 1;
} else {
r = mid - 1;
}
}
d[pos + 1] = nums[i];
}
}
return len;
}
};
- 时间复杂度:O(nlogn)。数组 nums 的长度为 n,我们依次用数组中的元素去更新 d 数组,而更新 d 数组时需要进行 O(logn) 的二分搜索,所以总时间复杂度为 O(nlogn)
- 空间复杂度:O(n),需要额外使用长度为 n 的 d 数组。