[Leetcode] 300. Longest Increasing Subsequence

(I

这题CLRS有,O(n^2)的解是比较典型的DP思路。DP的递归式如下
f(i) = max(1, max(f(q1), ... f(qn)) + 1); (其中q1..qn是nums[qn] < nums[i]的集合) 。根据这个递归式我们就可以知道代码如下:

    public int lengthOfLIS(int[] nums) {
        int[] dp = new int[nums.length];
        int result = 0;
        for (int i = 0; i < nums.length; i++) {
            dp[i] = 1;
            for (int j = 0; j < i; j++) {
                if (nums[j] < nums[i]) {
                    dp[i] = Math.max(dp[j] + 1, dp[i]);
                }
            }
            result = Math.max(dp[i], result);
        }
        
        return result;
    }

 

至于nlogn的解法。就不太接近正常DP的思想了。做法基于二分查找以及DP。

和DP一样,你需要一个缓存数组,数组里面放的东西,唔,难以描述。这个缓存数组是递增的但它并不是输入数组的LIS。因为它在不停尝试着构造可能是LIS的东西。这是一个虽然不是LIS但是能够构造LIS长度的一个东西。

举个例子说一下比较清楚,

譬如说1,24,3,53,20,22,24,13,42,首先肉眼可见,LIS是1,3,20,22,24,42,长度为6。

缓存数组的构建过程是这样的:

1 - 1
24 - 1, 24
3 - 1, 3
53 - 1, 3, 53
20 - 1, 3, 20
22 - 1, 3, 20, 22
24 - 1, 3, 20, 22, 24
13 - 1, 3, 13, 22, 24
42 - 1, 3, 13, 22, 24, 42

最后缓存数组的结果和实际的LIS是有出入的。所以说这个缓存数组是在不停的尝试更新一个类似LIS的东西。它在某一步可能确实是LIS,但是整体来说并不是。它就根据LIS的规矩来维护这个缓存数组,如果新进来的数字比缓存任何数字都要大,那么缓存数组就往后加一个,如果它比中间任何一个要小,那就更新刚好比它大的数字,所以这个时候就是二分需要的时候了。所以,最后最后是NLOGN。

下面给出对应的代码:

    public int lengthOfLIS(int[] nums) {
        int[] dp = new int[nums.length];
        int result = -1;
        for (int i = 0; i < nums.length; i++) {
            if (result == -1 || dp[result] < nums[i]) {
                result++;
                dp[result] = nums[i];
            } else {
                int index = this._binarySearch(dp, 0, result, nums[i]);
                dp[index] = nums[i];
                result = Math.max(result, index);
            }
        }
        
        return result + 1;
    }
    
    private int _binarySearch(int[] nums, int head, int tail, int target) {
        while (head <= tail) {
            int mid = (head + tail) / 2;
            if (nums[mid] == target) {
                return mid;
            } else if (nums[mid] < target) {
                head = mid + 1;
            } else {
                tail = mid - 1;
            }
        }
        
        return head;
    }

if (result == -1 || dp[result] < nums[i])这一段是一个小的optimization,让代码从1ms变成了0ms。。其实可以不要的。。囧rz..

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值