动态规划:最大上升子序列

一个数的序列bi,当b1 < b2 < … < bS的时候,我们称这个序列是上升的。对于给定的一个序列(a1, a2, …,aN),我们可以得到一些上升的子序列(ai1, ai2, …, aiK),这里1 <= i1 < i2 < … < iK <=N。
比如,对于序列(1, 7, 3, 5, 9, 4, 8),有它的一些上升子序列,如(1, 7), (3, 4, 8)等等。这些子序列中最长的长度是4,比如子序列(1, 3, 5, 8).

问题描述如上,那么如何实现求解一个未知序列的最大上升子序列呢?首先应该进行问题分解,依旧以(1, 7, 3, 5, 9, 4, 8)为例,maxs[i]表示以i为终点的最大上升子序列长度,这里从1开始。

  1. 以第一位为终点的子序列,只有1个,maxs[1] = 1;
  2. 以第二位为终点的子序列,(1,7),maxs[2] = 2;
  3. 以第三位为终点的子序列,(1,7,3),maxs[3] = 2;
  4. 以第n位为终点的子序列,maxs[n] = t(t未知);

    那么现在问题就可以简化为求max数组中的最大值。即为最大上升子序列的长度。

    现在重点来了,我们如何来求得maxs呢。当我们以第n位为终点时,他的最大上升子序列maxs[n]为在第i(1 < i < n-1)位中,所有满足arr[i] < arr[n]的maxs[i]中的最大值加1。

    现在,问题可以说已经迎刃而解,那就让我们来通过美丽的代码实现他吧。

 function maxChildlen(arr) {
        var maxs = [],
            N = arr.length,
            max = 0,
            flag;

        for (var i = 0; i < N; i++) {
            flag = 0;
            maxs[i] = 1;
            for (var j = 0; j < i; j++) {
                if (arr[j] <= arr[i] && maxs[j] > flag) {
                    flag = maxs[j];
                }
            }
            maxs[i] = flag + 1;
            if (maxs[i] > max) {
                max = maxs[i];
            }
        }

        return max;
    }

算法改进:
从第一位开始,第一位进入数组b中;
第二位如果大于b[0],直接入栈b[1],否则,替换b[0];
第三位,如果大于b的最后一位,则入栈b,否则,在b中寻找大于arr[3]的最小位(下界),然后将其替换掉。

以此类推,第N位与b[b.length]进行比较,如果大于b[b.length];直接入栈b,否则在b中寻找大于arr[N]的下界,将其替换。

最后b的长度就是最大上升子序列的长度。

这样一来,我们可以将原来的两层循环,分为一个循环和一个查找,查找我们采用二分查找,从而将时间复杂度降为logn; 这样,算法总的时间复杂度有logn^2优化为nlogn。
贴代码:

  //最大上升子序列
  function maxlen(arr) {
        //存放最大上升子序列
        var maxarr = [],
            N = arr.length,
            len = 0;
        //最小长度为1
        maxarr[len] = arr[len];
        for (var i = 1; i < N; i++) {
            if (arr[i] > maxarr[len]) {
                maxarr[++len] = arr[i];
            } else {
                if ((len - 1) >= 0 && arr[i] >= maxarr[len - 1]) {
                    maxarr[len] = arr[i]
                }
            }
        }

        return maxarr;
    }

Nice!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值