动态规划,它来了(二)

joytrian
发布于 2022-7-7 17:03
浏览
0收藏

 

最长递增子序列
最长递增子序列,也称为LIS,是出现非常高频的动态规划算法之一。这里对应力扣300

给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。

子序列是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。

输入:nums = [0,1,0,3,2,3]
输出:4
解释:最长递增子序列是 [0,1,2,3],因此长度为 4 。


对于最长递增子序列,如果不考虑动态规划的方法,使用暴力枚举其实还是比较麻烦的,因为你不知道遇到比前面元素大的是否要递增。

比如 1 10 3 11 4 5,这个序列不能选取1 10 11而1 3 4 5才是最大的,所以暴力枚举所有情况的时间复杂度还是非常高的。

如果我们采取动态规划的方法,创建的dp[]数组,dp[i]表示以nums[i]结尾的最长递增子序列,而dp[i]的求解方式就是枚举i号前面的元素和对应结尾的最长子序列,找到一个元素值小于nums[i]并且递增序列最长,这样的时间复杂度为O(n2)。

状态转移方程为:

dp[i]=max(dp[j])+1, 其中0≤j<i且num[j]<num[i]

具体流程为:

动态规划,它来了(二)-鸿蒙开发者社区

实现代码为:

class Solution {
    public int lengthOfLIS(int[] nums) {
        int dp[]=new int[nums.length];
        int maxLen=1;
        dp[0]=1;
        for(int i=1;i<nums.length;i++){
            int max=0;//统计前面 末尾数字比自己小 最长递增子串
            for(int j=0;j<i;j++){//枚举
                //结尾数字小于当前数字 并且长度大于记录的最长
                if(nums[j]<nums[i]&&dp[j]>max){
                    max=dp[j];
                }
            }
            dp[i]=max+1;//前面最长 加上自己
            if(maxLen<dp[i])
                maxLen=dp[i];
        }
        return maxLen;
    }
}

 

不过这道题还有一个优化,可以优化成O(nlogn)的时间复杂度。

我们用dp记录以 nums[i] 结尾的最长子序列长度,纵观全局,我们希望在长度一致的情况下末尾的值能够尽量的小!

例如 2,3,9,5 …… 在前面最长的长度为3 我们愿意抛弃2,3,9 而全部使用2,3,5 。也就是对于一个值,我们希望这个值能更新以它为结尾的最长的序列的末尾值。

如果这个值更新不了最长的序列,那就尝试更新第二长的末尾值以防待用。例如 2,3,9,5,4,5 这个序列2,3,5更新2,3,9;然后2,3,4更新2,3,5 为最长的2,3,4,5做铺垫。

而这个思路的核心就是维护一个lenth[]数组,length[i]表示长度为i的子序列末尾最小值,因为我们每次顺序增加一个长度说明这个值比前面的都大(做了充分比较),所以这个数组也是个递增的,递增,那么在锁定位置更新最大长度序列尾值的时候可以使用二分法优化。

动态规划,它来了(二)-鸿蒙开发者社区

实现代码为:

class Solution {
    public int lengthOfLIS(int[] nums) {
        int length[]=new int[nums.length];
        int len=1;
        length[0]=nums[0];
        for(int i=1;i<nums.length;i++){
            int left=0,right=len;
            while (left<right){
                int mid=left+(right-left)/2;
                if(length[mid]<nums[i]){
                    left=mid+1;
                }else {
                    right=mid;
                }
            }
            length[left]=nums[i];
            if(right==len)
                len++;        
        }
        return len;
    }
}

 

文章转自公众号:bigsai

标签
已于2022-7-7 17:03:36修改
收藏
回复
举报
回复
    相关推荐