Longest Increasing Subsequence
求最长上升子序列,这是一道很经典的题,这道题有两种解法。一种是O(n2)的时间复杂度。用一个数组res记录从第一个节点开始到第i个节点的最长上升子序列。对于每一个点,我们从头开始遍历,如果碰到有num[j]<num[i]那么res[i]=res[j]+1,那么对于一个节点来说,res[i]=max(res[j])+1。
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
if(nums.size()==0||nums.size()==1) return nums.size();
vector<int> res(nums.size(),0);
res[0]=1;
for(int i=1;i<nums.size();i++){
int ans=res[i];
for(int j=0;j<i;j++){
if(nums[i]>nums[j]&&res[j]>ans) ans=res[j];
}
res[i]=ans+1;
}
int ans=res[0];
for(int i=1;i<nums.size();i++){
if(res[i]>ans) ans=res[i];
}
return ans;
}
};
另外一种方法是使用二分搜索,使用一个数组res记录当前有i个数字的升序序列的最后一个数的最小值。因此,当遍历数组时:
如果nums[i]>res[k],则res[k+1]=nums[i]
如果nums[i]<res[k],则对res从0到k-1进行二分搜索查找出j使res[j-1]<nums[i]<res[j],那么我们就找到了在j个数字的升序序列中最后一个数最小的数了。res[j]=nums[i]
如果nums[i]=res[k]不做任何反应。
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
//O(nlogn)
if(nums.size()==0||nums.size()==1) return nums.size();
vector<int> res(nums.size(),0);//记录i个上升序列的最小值
res[0]=nums[0];
int len=0;
for(int i=1;i<nums.size();i++){
if(nums[i]<res[0]) res[0]=nums[i];
else if(nums[i]>res[len]){
res[++len]=nums[i];
}
else{
res[biSearch(res,0,len,nums[i])]=nums[i];
}
}
return len+1;
}
int biSearch(vector<int> &res,int start,int end,int num){
int s=start;
int e=end;
while(s<=e){
int mid=s+(e-s)/2;
if(res[mid]==num) return mid;
else if(res[mid]>num) e=mid-1;
else if(res[mid]<num) s=mid+1;
}
return s;
}
};