LeetCode 300. Longest Increasing Subsequence C++

13 篇文章 0 订阅

Problem

题目链接

Solution

题意为给定一个数组,要你求最长递增子序列(PS子序列是可以不连续的,子串则必须连续)

动态规划解法,dp[i]为以i为结尾的最长递增子序列长度,那么对于0<=j<i,若nums[i]>nums[j],则i位置可以接在j位置后组成递增子序列,状态转移方程为dp[i]=max(dp[i],dp[j]+1)

最后再遍历整个dp数组,找出最长递增子序列的值。

class Solution {
public:
    int lengthOfLIS(vector<int>& nums) {
        int len=nums.size();
        if(!len) return 0;
        vector<int> dp(len,1);
        for(int i=1;i<len;++i){
            for(int j=0;j<i;++j){
                if(nums[i]>nums[j])
                    dp[i]=dp[i]>(dp[j]+1)?dp[i]:(dp[j]+1);
            }
        }
        int ans=1;
        for(auto x:dp) ans=ans>x?ans:x;
        return ans;
    }
};

题目提示可以用nlogn的时间复杂度解决LIS问题,查阅资料后了解到:

其实最长递增子序列和一种叫做 patience game 的纸牌游戏有关

首先,给你一排扑克牌,我们像遍历数组那样从左到右一张一张处理这些扑克牌,最终要把这些牌分成若干堆。

处理这些扑克牌要遵循以下规则:
只能把点数小的牌压到点数比它大的牌上。如果当前牌点数较大没有可以放置的堆,则新建一个堆,把这张牌放进去。如果当前牌有多个堆可供选择,则选择最左边的堆放置。

为什么遇到多个可选择堆的时候要放到最左边的堆上呢?因为这样可以保证牌堆顶的牌有序

按照上述规则执行,可以算出最长递增子序列,牌的堆数就是最长递增子序列的长度
在这里插入图片描述

基于上述过程,就可以写出用二分查找解决LIS问题的代码

class Solution {
public:
    int lengthOfLIS(vector<int>& nums) {
        int len=nums.size();
        if(!len) return 0;
        vector<int> top(len);
        
        int piles=0;
        for(int i=0;i<len;++i){
            int p=nums[i];
            int lo=0,hi=piles;
            
            while(lo<hi){
                int mid=(lo+hi)>>1;
                if(top[mid]>=p) hi=mid;
                else if(top[mid]<p) lo=mid+1;
            }
            
            if(lo>=piles) piles++;
            top[lo]=p;
        }
        return piles;
    }
};

Result

在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值