最长递增子序列
题目链接
给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。
子序列 是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。
示例 1:
输入:nums = [10,9,2,5,3,7,101,18]
输出:4
解释:最长递增子序列是 [2,3,7,101],因此长度为 4 。
示例 2:
输入:nums = [0,1,0,3,2,3]
输出:4
示例 3:
输入:nums = [7,7,7,7,7,7,7]
输出:1
提示:
1
<
=
n
u
m
s
.
l
e
n
g
t
h
<
=
2500
−
1
0
4
<
=
n
u
m
s
[
i
]
<
=
1
0
4
1 <= nums.length <= 2500\\ -10^4 <= nums[i] <= 10^4
1<=nums.length<=2500−104<=nums[i]<=104
进阶:
你能将算法的时间复杂度降低到 O(n log(n)) 吗?
解题思路
思路1
- 动态规划,dp[i]代表以索引i元素为结尾的最长上升子序列
- 动态规划转移方程
dp[i]=max(dp[i],dp[j]+1)
且nums[j]<nums[i]
- 时间复杂度 O ( n 2 ) O(n^2) O(n2),空间复杂度 O ( n ) O(n) O(n)
思路2
- 时间复杂度 O ( n l o g n ) O(nlogn) O(nlogn),空间复杂度 O ( n ) O(n) O(n)
- 二分+贪心
- dp[i]代表长度为
i
的子序列末尾最小元素 - dp数组是一个单调递增的数组,我们通过二分不断更新长度为
i
的子序列末尾最小元素即可
解题代码
代码1
class Solution {
public:
int dp[2501];
int lengthOfLIS(vector<int>& nums) {
int ans=0;
for(int i=0;i<nums.size();i++){
dp[i]=1;
for(int j=0;j<i;j++){
if(nums[j]<nums[i]){
dp[i]=max(dp[i],dp[j]+1);
}
}
ans=max(ans,dp[i]);
}
return ans;
}
};
代码2
class Solution {
public:
int dp[2501];
int len=0;
int lengthOfLIS(vector<int>& nums) {
for(int i=0;i<nums.size();i++){
if(len==0){
dp[len++]=nums[i];
}
else{
int pos = lower_bound(dp,dp+len,nums[i])-dp;
dp[pos]=nums[i];
len=max(len,pos+1);
}
}
return len;
}
};