2021年9月27日-最长递增子序列

最长递增子序列

方法一:dp[i] 表示以 nums[i] 结尾的递增子序列的最大长度,复杂略高

// 时间复杂度高
public int lengthOfLIS(int[] nums) {
    // dp[i] 以 nums[i] 为结尾的严格递增子序列
    int[] dp = new int[nums.length];
    dp[0] = 1;
    int max = 1;
    for (int i = 1; i < dp.length; i++) {
        for (int j = i - 1; j >= 0; j--) {
            if (nums[i] > nums[j]) {
                dp[i] = Math.max(dp[i], dp[j]);
            }
        }
        dp[i] += 1;
        max = Math.max(dp[i], max);
    }
    return max;
}

方法二:如果有一个数组 tail[i] 保存了长度为 i+1 的递增子序列各种情况下最小的尾项,那么我们就有更大的几率在后面找到比 tail[i] 大的项,以增加最大子序列的长度

// 贪心 + 二分查找
public int lengthOfLISPro(int[] nums) {
    // tail[i] 表示子序列长度为 i+1 时,最后一个数字
    int[] tail = new int[nums.length];
    tail[0] = nums[0];
    int len = 1;
    for (int i = 1; i < nums.length; i++) {
        if (nums[i] > tail[len - 1]) {
            tail[len] = nums[i];
            len++;
        } else {
            // 二分查找,找最后一个比 num[i] 小的 tail[j],用 num[i] 更新 tail[j + 1]
            // 这就说明可以在 tail[j] 对应的数字后接上 num[i],构成长度为 j + 2 的子串,而且这个子串的末尾项即 num[i] 小于 目前的 tail[j + 1]
            // 所以为了维护 tail 数组要进行替换
            int low = 0, high = len - 1;
            while (low <= high) {
                int cen = (high - low) / 2 + low;
                if (tail[cen] >= nums[i]) {
                    high = cen - 1;
                } else {
                    low = cen + 1;
                }
            }
            tail[high + 1] = nums[i];
        }
    }
    return len;
}

这个动态规划的数组索引是答案,而以前都是数组内容作为答案

动态规划真的难顶。。。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值