我们如何在O(n log n)时间内从阵列的每个位置开始找到最长的增加子序列,我已经看到了在阵列的每个位置找到最长增长序列的技术,但我无法找到反过来说。
e.g。 对于序列“3 2 4 4 3 2 3” 输出必须是“2 2 1 1 1 2 1”
答案 0 :(得分: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]
将表示从值n
开始找到的最长子序列(位于当前位置的右侧)
循环如下:对于每个索引,我们在tmpArray
中查找值(以及所有更高的值),看看我们是否已经找到了可以预先附加值的子序列。如果我们找到一个,我们只需在该长度上加1,更新值的tmpArray
,然后移到下一个索引。如果我们找不到工作(更高)的子序列,我们将值的tmpArray
设置为1并继续。
为了使它成为O(n log n),我们观察到tmpArray
将始终是一个递减的数组 - 它可以而且应该使用二进制搜索而不是部分循环。
答案 1 :(得分: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; }
}