最长上升子序列

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;
    }
};



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值