【问题标题】:Can someone explain to me the Rabin-Karp algorithm's complexity?有人可以向我解释 Rabin-Karp 算法的复杂性吗?
【发布时间】:2017-01-17 08:44:33
【问题描述】:

我试图理解为什么 Rabin-Karp 算法的最坏情况运行时间是 O(nm) 而平均情况是 O(n+m)。

有人可以帮我吗?

【问题讨论】:

标签: algorithm time-complexity big-o string-matching rabin-karp


【解决方案1】:

Wiki 很好地解释了算法的时间复杂度。

可以说,hash计算函数的有效性(读作在恒定时间内动态重用已经计算好的hash值的能力)是决定性因素算法时间复杂度的计算。

让我们看看哈希计算是如何产生这种差异的。


时间复杂度为O(nm),适用于以下情况:

call hash(s[1..m])                  // O(m) additive
for index from 1 to n-m+1           // O(n)
    //Code to check if substring matches
    call hash(s[index+1..index+m])  // Inefficient hash function, takes O(m), just like naive string matching

O(nm) 相比,加法 O(m) 在很大程度上被忽略

给予,O(m) + O(n)*O(m) = O(nm)


时间复杂度为O(n+m),适用于以下情况:

call hash(s[1..m])                  // O(m) additive
for index from 1 to n-m+1           // O(n)
    //Code to check if substring matches
    call hash(s[index+1..index+m])  //Efficient hash function which takes only O(1), applies Rolling Hashing

给予,O(m) + O(n)*O(1) = O(m) + O(n) = O(m+n)

【讨论】:

    【解决方案2】:

    Rabin-Karp 是最坏情况 O(nm),因为它可能在每个点都发现误报(其中有 n),并且可能需要最多 m 比较验证匹配,因为您需要实际比较字符串。

    使用一个不应该发生的甚至一半合理的散列函数,但是对于任何散列函数来说,都可以制作一个查询(即,正在搜索的字符串和子字符串),它表现出上述情况病态行为。

    因此,尽管 R-K 预计时间复杂度为 O(n),但最坏情况的时间复杂度为 O(nm)。 (注意:由于m 必须不大于n,所以n + m2n 为界,因此O(n + m) 与O(n) 相同。)

    如果问题是找到 所有 匹配的子字符串,则更容易产生 O(nm) 行为,这是另一个经常使用 R-K 的上下文。在这种情况下,在由n as 组成的字符串中搜索由m as 组成的子字符串肯定会花费nm 时间,因为子字符串需要在源字符串中的每个点匹配。

    存在其他算法来查找在 n 中仍然是线性的所有子字符串,即使在病态情况下也是如此。

    【讨论】:

    • 感谢您的帮助!现在我了解了最坏情况的运行时间复杂度..但我仍然不了解该算法的平均情况..你能解释一下吗?
    • @user6812711:我概述的场景极为罕见。通常,很少或没有误报,并且仅通过查看第一个或两个字符来识别少数误报。所以几乎总是需要 O(n) 来找到正确的字符串,而 O(m) 来验证它是否正确。正如我在答案中解释的那样,由于m<n,O(n+m) 就是 O(n)。如果不明显,请阅读任何有关大 O 表示法的标准文本以理解这一点。
    猜你喜欢
    • 2019-08-18
    • 2012-10-17
    • 2022-08-19
    • 2022-01-10
    • 1970-01-01
    • 2023-03-25
    • 1970-01-01
    • 2022-01-18
    • 2018-04-09
    相关资源
    最近更新 更多