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

来源:互联网 发布:mysql deadlock 编辑:程序博客网 时间:2024/03/29 06:37

一个数的序列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
原创粉丝点击