Boyer-Moore Galil规则

时间:2016-07-05 15:04:57

标签: algorithm substring

当我了解Boyer-Moore Algorithm时,我正在Python中为子字符串搜索实现Galil Rule。我在网上浏览了加利尔规则,但我找不到任何更多的句子,我无法访问原始论文。如何将其实现到我当前的算法中?

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

注意:

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

实施例: aaabcb

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

我发现的几句话已经说过跟踪我内循环中第一次不匹配的时间(j,如果内循环内的if语句是True)和我开始比较的位置(i + j,在我的情况下)。我理解直觉,我已经检查过它们之间的所有指数,所以我不应该再做那些比较。我只是不明白如何连接点并实现。

2 个答案:

答案 0 :(得分:4)

Galil规则是利用模式中的周期性来减少比较。假设你有一个模式abcabcab。它是周期性最小的句点abc。通常,如果字符串P使UP的前缀,则模式UUUUU...是周期性的。 (在上面的示例中,abcabcab显然是重复字符串abc = U的前缀。)我们将最短的字符串称为P的句点。假设该句点的长度为k(在k = 3之后的U = abc中的示例中)。

首先,请记住,在文本中发现P后,Galil规则仅应用 。当你这样做时,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(否则无法保证模式与之前的匹配项对齐)。

现在,您可能想知道如何确定给定模式k的{​​{1}}。您需要首先计算后缀数组P,其中N将是前缀N[i]P[0, i]的最长公共后缀的长度。 (您可以使用Z算法计算P reverse 上的前缀数组Z来计算后缀数组,例如here所述。)获得后缀数组后,您可以轻松找到P,因为它是最小的kk > 0(其中N[m - k - 1] == m - k)。

例如:

m = |P|

答案 1 :(得分:1)

@Lajos Nagy的回答完美地解释了Galil规则的思想,但是我们有一种更简单的方法来计算k

只需使用KMP算法的前缀功能。

prefix[i]表示P[0..i]的最长适当前缀,它也是后缀。

然后k = m-prefix[m-1]

This article has explained the details.