300. 最长上升子序列

37 篇文章 0 订阅
31 篇文章 0 订阅

300. 最长递增子序列

给定一个无序的整数数组,找到其中最长上升子序列的长度。

示例:

输入: [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

 

基本思路对于子序列最值问题,子序列尾部元素是否被选中是一个很重要的隐含状态,它可以帮忙递推下一个的状态,动态规划,dp[i]表示以i为终点的最长上升长度。

  • 对于一个严格递增的子序列,当前元素是否能续上,主要是比较当前元素和改子序列的尾部元素的大小关系
  • 所以可以设计一个dp[i],表示以i结尾的最长上升序列,dp[i]=max(dp[j]+1,dp[i]) if dp[i]>dp[j]
    int lengthOfLIS(vector<int>& nums) {
        if(nums.size()==0)
            return 0;
        int maxLen=1;
        vector<int> dp(nums.size(),1);
        for(int i=1;i<dp.size();i++){
            for(int j=0;j<i;j++){
                if(nums[j]<nums[i]){
                    dp[i]=max(dp[i],dp[j]+1);
                }
            }
            maxLen=max(maxLen,dp[i]);
        }
        return maxLen;
    }

基本思路:贪心算法,如果要让上升序列尽可能的长,那么就尽量让序列上升的尽可能地缓慢,即尾部元素尽可能的小,据此,设置一个tail数据,tail[i]表示长度为i+1的序列的末尾的最小值,end为有效tail的末端。

  • 初始值,tail[0]=nums[0]
  • 若nums[i]>tail[end],则tail[++end]=nums[i]
  • 否则,二分查找插入tail数组
有插入过程可知tail数组一定是有序的(0~end之间),且严格递增。

证明:
    反证法,设i<j,但是tail[j]<=tail[i],对于tail[i]一定存在a0<a1...<ai;对于tail[j]一定存在b0<b1<...<bi<...bj;有定义可知ai>=bj>bi,那么必然存在b0<b1<...<bi<ai,这与tail[i]的定义不符,ai不是最小的元素。
class Solution {
public:
    int lengthOfLIS(vector<int>& nums) {
        if(nums.size()==0)
            return 0;
        vector<int> tail(nums.size(),0);
        tail[0]=nums[0];
        int end=0;
        for(int i=1;i<nums.size();i++){
            if(nums[i]>tail[end]){
                tail[++end]=nums[i];
            }
            else{
                int left=0;
                int right=end;
                while(left<right){
                    int mid=left+(right-left)/2;
                    if(tail[mid]<nums[i]){
                        left=mid+1;
                    }
                    else{
                        right=mid;
                    }
                }
                tail[left]=nums[i];

            }
        }

        end++;
        return end;
    }
};

同上,另外一种表示

    int lengthOfLIS(vector<int>& nums) {
        vector<int> dp(nums.size(),1);
        int ans=1;
        for(int i=1;i<nums.size();i++){
            for(int j=0;j<i;j++){
                if(nums[i]>nums[j]){
                    dp[i]=max(dp[j]+1,dp[i]);
                }
            }
            ans=max(ans,dp[i]);
        }
        return ans;
    }

类似题目:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值