【问题标题】:How to speed up calculation of length of longest common substring?如何加快最长公共子串长度的计算?
【发布时间】:2011-02-12 04:37:39
【问题描述】:

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

一种方法是使用后缀树(应该有很好的复杂性,虽然实现很复杂),另一种是动态规划方法(两者都提到在上面链接的维基百科页面上)。

使用动态规划

问题在于动态规划方法运行时间巨大(复杂度为O(n*m),其中nm是两个字符串的长度)。

我想知道的(在开始实现后缀树之前):如果我只想知道公共子串的长度(而不是公共子串本身),是否可以加快算法速度?

【问题讨论】:

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


    【解决方案1】:

    这些将使它运行得更快,尽管它仍然是O(nm)

    一个优化是在空间中(这可能会为您节省一点分配时间)注意到LCSuff 仅取决于前一行 - 因此如果您只关心长度,您可以优化O(nm) 空间到O(min(n,m))

    这个想法是只保留两行 - 您正在处理的当前行,以及您刚刚处理的前一行,并丢弃其余的行。

    【讨论】:

    • @Larry:谢谢!不过,我已经实现了这个。你还有其他的想法吗?
    • 另一种是实现自上而下和自下而上。您可以应用一些自上而下的分支和绑定技术来加快速度,并可能跳过永远不需要的状态。
    【解决方案2】:

    在实践中会更快吗?是的。 Big-Oh会更快吗?不,动态规划解总是 O(n*m)。

    使用后缀树可能会遇到的问题是,您用后缀树的线性时间扫描换取了空间上的巨大损失。后缀树通常比您需要为算法的动态编程版本实现的表大得多。根据字符串的长度,动态编程完全有可能更快。

    祝你好运:)

    【讨论】:

    • @Billy ONeal:你在比较后缀树和动态规划吗?我不是在要求那个。 What I what to know is that is there a way to make the dynamic programming algorithm faster if I only want to know the length of the common substring?
    • @eSKay:我相信我回答的第一部分回答了这个问题。
    • @eSKay:查找长度和查找实际字符串的算法是相同的。唯一的区别是查找实际字符串的算法将实际字符串与该长度一起存储在表中。通过不存储字符串,您可以更快,因为您花费更少的时间分配字符串。因此,它更快,但就 Big-Oh 而言不是。
    【解决方案3】:

    这是一个简单的算法,可以在 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];
    

    【讨论】:

      【解决方案4】:

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

      【讨论】:

      • @Lance:“使用 X 命名的规范算法”绝对是一个答案,尽管有点稀疏。
      • 嗯,我不记得发表过这样的评论。对不起。如果有的话,我会说它是一个仅限链接的答案。
      猜你喜欢
      • 1970-01-01
      • 2014-04-14
      • 2014-07-20
      • 1970-01-01
      • 2016-06-03
      • 2010-11-28
      • 1970-01-01
      • 2017-05-22
      • 2015-06-23
      相关资源
      最近更新 更多