如何加快最长公共子串长度的计算?

时间:2010-04-25 21:19:26

标签: c++ algorithm dynamic-programming suffix-tree lcs

我有两个非常大的字符串,我正在尝试查找他们的Longest Common Substring

一种方法是使用后缀树(假设具有非常好的复杂性,虽然是复杂的实现),另一种方法是动态编程方法(两者都提到在上面链接的维基百科页面上。)

使用动态编程 alt text

问题是动态编程方法的运行时间很长(复杂度为O(n*m),其中nm是两个字符串的长度。)

我想知道什么(在跳转到实现后缀树之前):如果我只想知道公共子串的长度(而不是公共子串本身),是否可以加速算法? /强>

4 个答案:

答案 0 :(得分:3)

这些会让它运行得更快,但它仍然是O(nm)

一个优化是在空间中(这可能会节省一点分配时间)注意到LCSuff仅依赖于前一行 - 因此如果您只关心长度,则可以优化{{1空格到O(nm)

我们的想法是只保留两行 - 您正在处理的当前行以及刚刚处理的上一行,然后丢弃其余行。

答案 1 :(得分:2)

实践中会更快吗?是。关于Big-Oh会更快吗?不可以。动态编程解决方案始终为O(n * m)。

您可能遇到的后缀树问题是您使用后缀树的线性时间扫描进行交易,以获得巨大的空间惩罚。后缀树通常比您需要为算法的动态编程版本实现的表大得多。根据字符串的长度,动态编程完全可能更快。

祝你好运:)

答案 2 :(得分:0)

这里是一个简单的算法,它可以在O((m + n)* log(m + n))中完成,并且与后缀树算法(O(m + n)运行时)相比更容易实现。

让它从最小公共长度(minL)= 0开始,最大公共长度(maxL)= min(m + n)+1。

1. if (minL == maxL - 1), the algorithm finished with common len = minL.

2. let L = (minL + maxL)/2

3. hash every substring of length L in S, with key = hash, val = startIndex.

4. hash every substring of length L in T, with key = hash, val = startIndex. check if any hash collision in to hashes. if yes. check whether whether they are really common substring. 

5. if there're really common substring of length L, set minL = L, otherwise set maxL = L. goto 1.

剩下的问题是如何在时间O(n)中散列长度为L的所有子字符串。您可以使用多项式公式如下:

Hash(string s, offset i, length L) = s[i] * p^(L-1) + s[i+1] * p^(L-2) + ... + s[i+L-2] * p + s[i+L-1]; choose any constant prime number p.

then Hash(s, i+1, L) = Hash(s, i, L) * p - s[i] * p^L + s[i+L];

答案 3 :(得分:-1)

Myer's bit vector algorithm可以帮到你。它通过使用位操作来工作,并且是一种更快的方法。