【问题标题】:How to find longest increasing sequence starting at each position within the array in O(n log n) time,如何在 O(n log n) 时间内找到从数组中每个位置开始的最长递增序列,
【发布时间】:2012-10-08 13:18:49
【问题描述】:

我们如何在 O(n log n) 时间内找到从数组的每个位置开始的最长递增子序列,我已经看到了找到在数组的每个位置结束的最长递增序列的技术,但我找不到反过来。

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

【问题讨论】:

  • 第一个输出不应该是1吗?
  • @leppie 抱歉它应该是子序列,所以 3,4 是有效的子序列
  • @quasiverse 你能详细说明如何倒退吗?
  • 反转数组;找到在每个位置结束的 LIS(这可以在 O(n) 时间内完成);反转结果。
  • @j_random_hacker:你确定它可以在 O(n) 时间内完成吗?如果他询问的是连续子序列,那将是微不足道的,但他需要一般的 LIS,如果有记忆的话,它是 O(n log n)。

标签: algorithm optimization data-structures sequence dynamic-programming


【解决方案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 将始终是一个递减数组——它可以而且应该使用二分查找而不是部分循环。

【讨论】:

    【解决方案2】:

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

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

    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; }
    }
    

    【讨论】:

    • 这将在线性时间内找到最长的增加子字符串。允许子序列 跳过任意数量的元素,这使它成为一个更棘手的问题。例如。 2 3 4 10 是您的示例序列的子序列。 (是的,术语有点混乱……)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-04-03
    • 2014-02-25
    • 1970-01-01
    • 2020-09-15
    • 2011-11-29
    • 2012-06-24
    • 1970-01-01
    相关资源
    最近更新 更多