【问题标题】:Boyer-Moore Galil RuleBoyer-Moore Galil 规则
【发布时间】:2016-07-05 15:04:56
【问题描述】:

当我了解Galil Rule 时,我正在实现Boyer-Moore Algorithm 以在Python 中进行子字符串搜索。我在网上四处寻找加利尔规则,但除了几句话外,我没有找到任何东西,而且我无法访问原始论文。如何在我当前的算法中实现这一点?

i = 0
while i < (N - M + 1):
    skip = 0
    for j in reversed(range(0, M)):
        if pattern[j] != text[i + j]:
            skip = max(1, j - offsets[text[i+j]])
            break
    if skip == 0:
        return i
    i += skip
return -1

注意事项:

  • offsets[c] = -1 如果 c 不在模式中
  • offsets[c] = 模式中 c 的最后一个索引

示例: aaabcb

  • 偏移量[a] = 2
  • 偏移量[b] = 5
  • 偏移量[c] = 4
  • 偏移量[d] = -1

我发现的几句话说要跟踪我的内部循环中第一次不匹配发生的时间(j,如果内部循环中的 if 语句为 True)以及我开始比较的位置(i + j,就我而言)。我理解我已经检查了它们之间的所有索引的直觉,所以我不应该再次进行这些比较。我只是不明白如何连接这些点并实现一个实现。

【问题讨论】:

标签: algorithm substring


【解决方案1】:

Galil 规则是关于利用模式中的周期性来减少比较。假设您有一个模式abcabcab。它是周期性的,最小周期abc。一般来说,如果有一个字符串U 使得PUUUUU... 的前缀,则模式P 是周期性的。 (在上面的例子中,abcabcab 显然是重复字符串abc = U 的前缀。)我们称最短的这样的字符串为P。让这段时间的长度为k(在上面的例子中k = 3,因为U = abc)。

首先,请记住,Galil 规则在您发现文本中出现P 之后才适用。当你这样做时,Galil 规则说你可以移动k(模式的周期性),你只需要比较现在移动模式的最后一个k 字符来确定是否有匹配。

这是一个例子:

P = ababa
T = bababababab
U = ab
k = 2

第一次出现:b[ababa]babab。现在你可以移动k = 2,你只需要检查模式的最后两个字符:

T = bababa[ba]bab
P =    aba[ba]       // Only need to compare chars inside brackets for next match.

P 的其余部分 必须 匹配,因为 P 是周期性的,并且您将其移动了它的周期 k 从现有匹配(这是至关重要的)所以重复的部分会很好地排列。

如果您找到了另一个匹配项,请重复。但是,如果您发现不匹配,您将恢复到标准的 Boyer-Moore 算法,直到找到另一个匹配。请记住,您只能在找到匹配项时使用 Galil 规则并且您移动了 k(否则不能保证该模式与之前的匹配项对齐)。

现在,您可能想知道,如何确定给定模式 Pk。您需要首先计算后缀数组N,其中N[i] 将是前缀P[0, i]P 的最长公共后缀的长度。 (您可以通过使用 Z 算法计算 Preverse 上的前缀数组 Z 来计算后缀数组,例如,如 here 所述。)一旦你有了后缀数组,您可以轻松找到k,因为它将是最小的k &gt; 0,例如N[m - k - 1] == m - k(其中m = |P|)。

例如:

P = ababa
m = 5
N = [1, 0, 3, 0, 5]
k = 2  because  N[m - k - 1] == N[5 - 2 - 1] == N[2] == 3 == 5 - k

【讨论】:

    【解决方案2】:

    @Lajos Nagy 的回答完美地解释了 Galil 规则的概念,但是我们有一个更直接的方法来计算 k

    只需使用KMP算法的前缀函数即可。

    prefix[i] 表示P[0..i] 的最长专有前缀,也是一个后缀。

    还有,k = m-prefix[m-1]

    This article has explained the details.

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-06-21
      • 2016-04-13
      • 2014-06-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多