首页 > 其他 > 详细

【LeetCode从零单刷】Longest Increasing Subsequence

时间:2015-11-05 18:54:57      阅读:454      评论:0      收藏:0      [点我收藏+]

题目:

Given an unsorted array of integers, find the length of longest increasing subsequence.

For example, Given [10, 9, 2, 5, 3, 7, 101, 18],
The longest increasing subsequence is [2, 3, 7, 101], therefore the length is 4. Note that there may be more than one LIS combination, it is only necessary for you to return the length.

Your algorithm should run in O(n2) complexity.

Follow up: Could you improve it to O(n log n) time complexity?

解答:

寻找最长上升子序列(LIS),最基本的方法是动态规划。转移方程为 dp[i] = max{dp[j]} + 1 ( -1< j < i && nums[j] < nums[i])。

解释也非常直观:dp[i] 表示如果取得当前 i 元素,所能达到的最长 LIS。如果需要打印出此序列,仅需要保存上一个元素。

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

如果要修改到 O(n log n) time complexity?贪心法 + 二分搜索

增加一条辅助的顺序(ordered)栈(队列……完成任务就好),保存尽可能长的LIS。入栈的要求为:

  1. 将a[0]入栈
  2. 每次取栈顶元素top(最大元素)和读到的元素a[i](0<i<n)做比较:
  3. - 如果a[i] > top 则将a[i]入栈;
  4. - 如果a[i] <= top则二分查找栈中的比a[i]大的第1个数,并用a[i]替换它(如果栈顶元素被替换,说明有机会到达更长序列);
  5. 最长序列长度即为栈的大小

直观理解:对于 x 和 y,如果 x < y 且 stack[y] < stack[x],用 stack[x] 替换 stack[y],此时的最长序列长度没有改变,但序列继续变长的‘‘潜力‘‘增大,这就是贪心的目标。

举例:原序列为1,5,8,3,6,7

开始1,5,8相继入栈,此时读到3,用3替换5,得到1,3,8;再读6,用6替换8,得到1,3,6;再读7,得到最终栈为1,3,6,7。最长递增子序列为长度4

但是这个方法,有一个很大的缺陷:只能保证序列长度的正确性,不能保证栈中就是正确的序列

举例:原序列为1,5,8,2,栈内最后是 1,2,8 不是正确的序列。

分析一下,我们可以看出,虽然有些时候这样得不到正确的序列,但最后算出来的个数是没错的,为什么呢?

当a[i]>top时,总个数直接加1,这肯定没错;但当a[i]<top时呢? 这时a[i] 会替换栈里面的某一个元素,总个数不变。如果求具体序列,还是动态规划比较好。

class Solution {
public:
    int lengthOfLIS(vector<int>& nums) {
        vector<int> LIS;
        for (int i = 0; i < nums.size(); i++) {
            if (LIS.size() == 0 || LIS[LIS.size() - 1] < nums[i]) {
                LIS.push_back(nums[i]);
            }
            else {
                int l = 0, r = LIS.size() - 1;
                while (l < r) {
                    int m = (l + r) / 2;
                    if (LIS[m] >= nums[i]) {
                        r = m;
                    }
                    else {
                        l = m + 1;
                    }
                }
                LIS[l] = nums[i];
            }
        }
        return LIS.size();
    }
};

参考资料:

https://en.wikipedia.org/wiki/Longest_increasing_subsequence

http://blog.csdn.net/yorkcai/article/details/8651895

https://leetcode.com/discuss/67888/c-clean-o-nlogn-code-using-binary-search

版权声明:本文为博主原创文章,转载请联系我的新浪微博 @iamironyoung

【LeetCode从零单刷】Longest Increasing Subsequence

原文:http://blog.csdn.net/ironyoung/article/details/49664087

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!