Rabin Karp算法 - 给定输入的最坏情况O(m * n)如何?

时间:2016-08-20 14:01:36

标签: algorithm rabin-karp

在顶级编码器的RK算法代码中:

// correctly calculates a mod b even if a < 0
function int_mod(int a, int b)
{
  return (a % b + b) % b;
}

function Rabin_Karp(text[], pattern[])
{
  // let n be the size of the text, m the size of the
  // pattern, B - the base of the numeral system,
  // and M - a big enough prime number

  if(n < m) return; // no match is possible

  // calculate the hash value of the pattern
  hp = 0;
  for(i = 0; i < m; i++) 
    hp = int_mod(hp * B + pattern[i], M);

  // calculate the hash value of the first segment 
  // of the text of length m
  ht = 0;
  for(i = 0; i < m; i++) 
    ht = int_mod(ht * B + text[i], M);

  if(ht == hp) check character by character if the first
               segment of the text matches the pattern;

  // start the "rolling hash" - for every next character in
  // the text calculate the hash value of the new segment
  // of length m; E = (Bm-1) modulo M            
  for(i = m; i < n; i++) {
    ht = int_mod(ht - int_mod(text[i - m] * E, M), M);
    ht = int_mod(ht * B, M);
    ht = int_mod(ht + text[i], M);

    if(ht == hp) check character by character if the
                 current segment of the text matches
                 the pattern; 
  }
}

写的是

  

不幸的是,仍有一些情况我们必须为文本中的每个起始位置运行“天真”方法的整个内循环 - 例如,在字符串“aaaaaaaaaaaaaaaaaaaaaaa”中搜索模式“aaa”时 - 所以在最坏的情况下,我们仍然需要(n * m)次迭代。

但是,算法不会在第一次迭代时停止 - 就像它会看到前三个字母是&#39; a&#39;哪个与针匹配?

2 个答案:

答案 0 :(得分:1)

假设我们要搜索的字符串不是&#34; aaa&#34;而是一些其他字符串,其散列与&#34; aaa&#34;的散列相同。然后,每个点都需要进行比较。

当然,我们希望比较早于m个字符失败,但可能需要o(m)个字符。

话虽如此,RK的一个常见用途是找到所有(重叠)实例,在这种情况下引用的例子显然是o(mn)。

答案 1 :(得分:1)

Rabin-Karp算法保持计算大小为text的{​​{1}}的所有子字符串的哈希值,并将其与M的哈希值匹配。现在,可以有多个子字符串具有相同的哈希值。

因此,当pattern的哈希值和pattern的某些子字符串匹配时,我们需要再次迭代它们,以确保它们实际上是否相同。

如果是textpattern = "AAA",则有text = "AAAAAAAAAAAAA"个子字符串与O(n)的哈希值匹配。对于每场比赛,我们需要在pattern时间内进行迭代确认;因此最坏情况的复杂性O(m)