我有两个非常大的字符串,我正在尝试查找他们的Longest Common Substring。
一种方法是使用后缀树(假设具有非常好的复杂性,虽然是复杂的实现),另一种方法是动态编程方法(两者都提到在上面链接的维基百科页面上。)
使用动态编程
问题是动态编程方法的运行时间很长(复杂度为O(n*m)
,其中n
和m
是两个字符串的长度。)
我想知道什么(在跳转到实现后缀树之前):如果我只想知道公共子串的长度(而不是公共子串本身),是否可以加速算法? /强>
答案 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可以帮到你。它通过使用位操作来工作,并且是一种更快的方法。