我们如何在 O(n log n) 时间内找到从数组的每个位置开始的最长递增子序列,我已经看到了找到在数组的每个位置结束的最长递增序列的技术,但我无法找到其他方式圆形的。
例如,对于序列“3 2 4 4 3 2 3”,输出必须是“2 2 1 1 1 2 1”
我们如何在 O(n log n) 时间内找到从数组的每个位置开始的最长递增子序列,我已经看到了找到在数组的每个位置结束的最长递增序列的技术,但我无法找到其他方式圆形的。
例如,对于序列“3 2 4 4 3 2 3”,输出必须是“2 2 1 1 1 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
将始终是一个递减数组——它可以而且应该使用二进制搜索而不是部分循环。
编辑:我没有完全阅读这篇文章,对不起。我认为您需要所有序列的最长递增子序列。重新编辑代码以使其工作。
我认为实际上可以在线性时间内完成。考虑这段代码:
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; }
}