要求:最长严格递增子序列长度
思路:动规,dp[i]应该表示以si结尾的还是到位置i的最长长度?注意到需要比较数字所以以si结尾直接比较si方便一些
法一:动规
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
int n=nums.size();
int dp[n];
int maxlen=1;
dp[0]=1;
for(int i=1;i<n;++i){
dp[i]=1;
for(int j=0;j<i;++j)
if(nums[i]>nums[j])
dp[i]=max(dp[i],1+dp[j]);
maxlen=max(maxlen,dp[i]);
}
return maxlen;
}
};
法二:时间要优化成O(nlogn)明显要来个二分,无序怎么二分?所以本题dp要换成有序的,dp直接存这个最长递增子序列(不一定是)。二分的目标是在dp中找到第一个(左边界,返回left)大于等于当前num的位置并且插入替代作为最长递增子序列dp的最后位置。注意的是,要么插尾要么直接替代,dp只会增长不会从头开始
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
int n=nums.size();
int dp[n];
dp[0]=nums[0];
int left=0,right=0;
int lastidx=0;
for(int i=1;i<n;++i){
while(left<=right){
int mid=(left+right)/2;
if(dp[mid]<nums[i])left=mid+1;
else right=mid-1;
}
dp[left]=nums[i];
lastidx=max(lastidx,left);
right=lastidx;
left=0;
}
return right+1;
}
};