在 O(NlogN) 时间内找到最长的公共子序列

Posted

技术标签:

【中文标题】在 O(NlogN) 时间内找到最长的公共子序列【英文标题】:Finding longest common subsequence in O(NlogN) time 【发布时间】:2015-08-26 10:18:39 【问题描述】:

有没有办法在 O(NlogN) 时间内找到两个序列的最长公共子序列?

我在某处读到有一种方法可以使用二进制搜索来实现这一点。

我知道需要 O(N2) 时间的 dp 方法。

【问题讨论】:

【参考方案1】:
vector <int> LIS;
int LongestIncreasingSubsequence(int n)
    if(!n) return 0;
    LIS.emplace_back(arr[0]);
    for(int i = 1; i < n; i++)
        if(arr[i] > LIS.back()) LIS.emplace_back(arr[i]);
        else *lower_bound(LIS.begin(), LIS.end(), arr[i]) = arr[i];
    
    return LIS.size();

【讨论】:

正如目前所写,您的答案尚不清楚。请edit 添加其他详细信息,以帮助其他人了解这如何解决所提出的问题。你可以找到更多关于如何写好答案的信息in the help center。【参考方案2】:

dynamic programming approach,一般情况下为 O(n2)。对于某些其他情况,有较低复杂度的算法:

对于固定的字母大小(不随 n 增长),Method of Four Russians 将时间缩短到 O(n2 /log n)(见here)。

参见here 另一个进一步优化的案例。

【讨论】:

还有非常实用的O(nd) approach of Meyers,其中 d 是两个字符串之间的 Levenshtein 距离——如果存在有限数量的差异,则为 O(n)。 TTBOMK 它仍然是 diff 中使用的。【参考方案3】:

假设Exponential Time Hypothesis(比 P 更严格不等于 NP,但仍被广泛认为是正确的),任何时间都不可能在 O(N^2 - eps)正常数 eps,请参阅 Karl Bringmann 和 Marvin Kunnemann 的 "Quadratic Conditional Lower Bounds for String Problems and Dynamic Time Warping"(arXiv 上的预印本可用)。

粗略地说,这意味着这个问题的一般情况不能比像 O(N^2/log N) 这样的东西更好地及时解决,所以如果你想要更快的算法,你必须考虑额外的约束(一些属性字符串)或寻找近似解决方案。

【讨论】:

【参考方案4】:

对于一般情况,O(N^2) 动态规划算法是你能做的最好的。但是,在某些特殊情况下存在更好的算法。

    字母大小有界

这是一种很常见的情况。由某些字母(例如英语)中的字母组成的序列属于这一类。对于这种情况,可以优化 O(N*M) 算法以获得具有method of four Russians 的 O(N^2/logN)。不知道具体怎么样,你可以搜索一下。

    两个序列都由不同的元素组成

一个示例问题是“给定从 1 到 N 的两个数字排列,找到它们的 LCS”。这个可以在 O(N*logN) 中解决。 让序列为 A 和 B。 定义一个序列C。C[i]是B[i]在A中的索引。(A[C[i]] = B[i]) A和B的LCS是C的longest increasing subsequence。

【讨论】:

第二种情况只要求一个字符串有不同的元素。【参考方案5】:

两个序列之间最长的公共子序列本质上是 n 平方的。

Masek and Patterson (1980) 使用所谓的“Four Russians”技术对 n-squared / log n 进行了小幅改进。

在大多数情况下,这种复杂的方法带来的额外复杂性并不能以微小的收益来证明。出于实际目的,您可以将 n 平方方法视为典型应用中的合理最优值。

【讨论】:

还有非常实用的O(nd) approach of Meyers,其中 d 是两个字符串之间的 Levenshtein 距离——如果存在有限数量的差异,则为 O(n)。 TTBOMK 它仍然是 diff 中使用的。

以上是关于在 O(NlogN) 时间内找到最长的公共子序列的主要内容,如果未能解决你的问题,请参考以下文章

C语言实现最长公共子串与最长公共子序列

最长不下降子序列 (O(nlogn)算法)

P3402 最长公共子序列(nlogn)

O(nlogn)最长递增子序列算法,如何输出所求子序列?

51nod 1134 最长递增子序列 (O(nlogn)算法)

最长递增子序列 LIS 时间复杂度O(nlogn)的Java实现