输入:nums = [10,9,2,5,3,7,101,18]
输出:4
解释:最长递增子序列是 [2,3,7,101],因此长度为 4 。
解法一:动态规划 O(n^2)
设 dp[i]是使用 nums[i]的最长子序列长度。则
d
p
[
i
]
=
{
m
a
x
(
d
p
[
j
]
+
1
)
nums[i]>nums[j],0<=j<i
d
p
[
i
]
else
dp[i]= \begin{cases} max(dp[j]+1)& \text{nums[i]>nums[j],0<=j<i}\\ dp[i]& \text{else} \end{cases}
dp[i]={max(dp[j]+1)dp[i]nums[i]>nums[j],0<=j<ielse
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
// dp[i] 的状态表示 nums[i]必须被取
int n=(int)nums.size();
if(n==0) return 0;
vector<int> dp(n,0);
for(int i=0;i<n;++i){
dp[i]=1;
for(int j=0;j<i;++j){
if(nums[j]<nums[i]) dp[i]=max(dp[i],dp[j]+1); //找到这个过程中最大 dp 值
}
}
return *max_element(dp.begin(),dp.end());
}
};
解法二 二分查找 O(NlogN)
放纸牌思想:设有一副扑克牌,放成 n堆,将点数小的放到点数大的上,如果当前没有一个堆的点数比当前牌大,则新建一个堆。最后的堆数即最终答案。
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
// 思路借鉴 labuladong放纸牌:一副扑克牌,放成 n堆,将点数小的放到点数大的上。最后的堆数即最终答案
int n=nums.size();
int dui=0;// 表示当前 dui 的个数。
vector<int> top(n);
for(auto target:nums){
// 二分查找找到当前n 堆牌的左边界,即找到比 target 大的左边界。
// dui 表示当前个数,right=dui,所以不能取到 right。所以采用左闭右开写法
int left=0,right=dui,ans=n+1;
while(left<right){
int mid=(left+right)/2;
if( top[mid]>=target){ans=mid;right=mid;}
else left=mid+1;
}
// 没有找到可以放纸牌的堆,所以新建一个堆。
if(ans==n+1){top[dui]=target;++dui;}
// 找到了,将该纸牌放入该堆的最上面
else top[ans]=target;
}
return dui;
}
};
参考 https://www.cnblogs.com/labuladong/p/12320272.html