最长递增子序列[动态规划+贪心+二分法练习]

前言

与其知道动态规划是什么,不如知道什么什么时候用动态规划。当一个问题可以被拆解成相同性质但规划更小的递归之问题时,则可动态规划。动态规划时,可能不是简单的取前一个子问题的值,也有可能结合贪心来取max()/min()。除此之外,当我们碰到有序,就可以联想到双指针/二分法,利用好有序条件,将时间复杂度降下来。

一、最长递增子序列

二、抓特点刨析问题

1、贪心+二分

// 最长递增子序列。
public class LengthOfLIS {
    /*
    target:找 最长严格递增子序列的 长度。子序列就意味着不能改变相对顺序。
    子序列如何找?
    这个子序列不要求连续,则不能简单的确定起点和终点找到子序列。
    将子序列存入list.
    每个元素具有 值属性 & 位置属性,后面的值要大于前面的值则可加入list

    有一个关键问题:已经有一个递增序列了,后面出现一个更小的递增序列怎么办?
    既然是从前往后遍历,那么在位置上,后一个元素都是满足位置条件的,那么这些小的递增序列就可以替代前面的大递增序列元素。
    毕竟不需要得到这个序列,只需要求长度。
     */
    public int lengthOfLIS(int[] nums) {
        List<Integer> arr = new ArrayList<>();

        for (int num : nums) {
            if (arr.size() == 0 || arr.get(arr.size() - 1) < num) arr.add(num);
            else {
                int idx = binarySearch(arr, num);
                arr.set(idx, num);
            }
        }
        return arr.size();
    }

    private int binarySearch(List<Integer> arr, int target) {
        int low = 0, high = arr.size() - 1;

        while (low < high) {
            // 取刚好等于或大于自己的那个位置。
            int mid = low + (high - low >>> 1);
            int midVal = arr.get(mid);

            if (midVal < target) low = mid + 1;
            else high = mid;
        }
        return low;
    }
}

2、动态规划+贪心

// 一题多解,打开视野。
class LengthOfLIS2 {
    /*
    target:找 最长严格递增子序列的 长度。子序列就意味着不能改变相对顺序。
    递增,要么是从前往后找大的;要么是从后往前找小的。
    问题拆解:从nums[0:n]的子序列最大递增长度,和nums[0:i]有关,0<=i<=n-1;
    拆解之后的问题和原问题有相同性质,却规模变得更小一些,所以可动态规划,很明显这里动起来需要取max,所以为DP + greed
    f[n] = max(f(x))当且仅当nums[n - 1] > nums[x - 1]
     */
    public int lengthOfLIS(int[] nums) {
        int n = nums.length;
        int[] f = new int[n + 1];

        int max = 1;
        for (int i = 1; i <= n; i++) {
            f[i] = 1;
            for (int j = 1; j < i; j++) {
                if (nums[i - 1] > nums[j - 1]) {
                    f[i] = Math.max(f[j] + 1, f[i]);
                }
            }
            max = Math.max(max, f[i]);
        }
        return max;
    }
}

总结

1)一题多解,打开视野。
2)贪心+DP,考察逻辑思维 & 数据结构基础的好题型。
3)抓问题特点/问题核心,刨析问题,联想/组合解决方案。

参考文献

[1] LeetCode 最长递增子序列

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值