0

我们如何在 O(n log n) 时间内找到从数组的每个位置开始的最长递增子序列,我已经看到了找到在数组的每个位置结束的最长递增序列的技术,但我无法找到其他方式圆形的。

例如,对于序列“3 2 4 4 3 2 3”,输出必须是“2 2 1 1 1 2 1”

4

2 回答 2

1

我做了一个快速而肮脏的 JavaScript 实现(注意:它是 O(n^2)):

function lis(a) {
    var tmpArr = Array(),
        result = Array(),
        i = a.length;

    while (i--) {
        var theValue = a[i],
            longestFound = tmpArr[theValue] || 1;

        for (var j=theValue+1; j<tmpArr.length; j++) {
            if (tmpArr[j] >= longestFound) {
                longestFound = tmpArr[j]+1;
            }
        }
        result[i] = tmpArr[theValue] = longestFound;
    }
    return result;
}

jsFiddle:http: //jsfiddle.net/Bwj9s/1/

我们从右到左遍历数组,将先前的计算保存在单独的临时数组中以供后续查找。

tmpArray包含先前找到的以任何给定值开头的子序列,因此将tmpArray[n]表示找到的最长子序列(在当前位置的右侧)以 value 开头n

循环是这样的:对于每个索引,我们在我们的索引中查找值(以及所有更高的值),tmpArray看看我们是否已经找到了可以将值添加到的子序列。如果我们找到一个,我们只需将该长度加 1,更新该tmpArray值,然后移动到下一个索引。如果我们没有找到工作(更高)的子序列,我们将tmpArray值设置为 1 并继续。


为了使它成为 O(n log n),我们观察到tmpArray将始终是一个递减数组——它可以而且应该使用二进制搜索而不是部分循环。

于 2012-10-18T07:38:50.570 回答
0

编辑:我没有完全阅读这篇文章,对不起。我认为您需要所有序列的最长递增子序列。重新编辑代码以使其工作。

我认为实际上可以在线性时间内完成。考虑这段代码:

int a[10] = {4, 2, 6, 10, 5, 3, 7, 5, 4, 10};
int maxLength[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // array of zeros
int n = 10; // size of the array;

int b = 0;


while (b != n) {
  int e = b;     
  while (++e < n && a[b] < a[e]) {} //while the sequence is increasing, ++e
  while (b != e) { maxLength[b++] = e-b-1; }
}
于 2012-10-18T08:27:18.100 回答