我正在阅读Cormen的书“算法导论”中的字符串算法。对于Transition,如下所示。
我的问题:我们为什么要做min(m+1, q+2)
,为什么我们将m增加1,q增加2.
以下链接已回到上述问题。
http://people.scs.carleton.ca/~maheshwa/courses/5703COMP/Fall2009/StringMatching.pdf
请用一个简单的例子来帮助。
Algorithm Compute-Transition-Function(P, Sigma)
m = length(P);
for q = 0 through m do
for each character x in Sigma
k = min(m+1, q+2);
repeat k = k-1 // work backwards from q+1
until Pk 'is-suffix-of' Pqx;
d(q, x) = k; // assign transition table
end for;
end for;
return d;
End algorithm.
答案 0 :(得分:2)
m + 1
,因为在下一个repeat
循环k
首先减少。q + 2
,因为在repeat
中您以q + 1
开始,因此至少有1个字符。
以下代码可能存在边界问题(缺少q == m), 但希望使索引更清晰。
m = length(P);
for q = 0 through m - 1 do // Loop through substrings [0, q+1]
for each character x in Sigma
k = q+1;
// work backwards from q+1
while not Pk 'is-suffix-of' Pqx;
do k = k-1; end do;
d(q, x) = k; // assign transition table
end for;
end for;
return d;
答案 1 :(得分:1)
代码已经解释过,所以这里有一个例子来看看发生了什么
假设字符串为nano
所以我们希望我们的状态与模式部分匹配。与"nano"
可能的部分匹配是
"", "n", "na", "nan", or (the complete match) "nano"
本身。换句话说,它们只是字符串的前缀。一般来说,如果模式有m个字符,我们需要m + 1个状态;这里m = 4,有五个州。
如果我们刚看到"...nan"
,并看到另一个角色"x"
,我们应该去哪个州?显然,如果x是匹配中的下一个字符(这里是“o”),我们应该转到下一个更长的前缀(这里是“nano”)。很明显,一旦我们看到完全匹配,我们就会保持这种状态。但是假设我们看到了不同的角色,例如"a"
?这意味着到目前为止,字符串看起来像"...nana"
。我们可以进行的最长部分匹配仅为"na"
,即我们可以使用最后2个字符。因此,从州"nan"
开始,我们应该绘制一个标有"a"
的箭头来表示"na"
。请注意,"na"
是"nano"
的前缀(因此它是一个状态),后缀为"nana"
(所以它是与我们刚看到的一致的部分匹配)。
通常,从状态+字符到状态的转换是最长的字符串,它同时是原始模式的前缀和我们刚看到的状态+字符的后缀。这足以告诉我们所有转换应该是什么。如果我们要查找模式"nano"
,则转换表将是
n a o other
--- --- --- ---
empty: "n" empty empty empty
"n": "n" "na" empty empty
"na": "nan" empty empty empty
"nan": "n" "na" "nano" empty //just as an illustration, nan + n = n because we can only use the last 'n', nan + a = na because now we can use the last two 'na'
"nano": "nano" "nano" "nano" "nano"
现在我们如何使用这个表来实际进行模式搜索?
在字符串"banananona"
上模拟这个,我们通过一次移动一个字符来获得状态序列为空,空,"n", "na", "nan", "na", "nan", "nano", "nano", "nano"
。由于我们以状态"nano"
结束,因此该字符串在其中包含"nano"
。所以让我们来看看最新情况以及如何使用上面的表格,在'b',我们没有任何可能的状态'n', 'na', 'nan', 'nano'
。因此它被视为空...与我们到达'ba'
时相同。当我们点击下一个字符'n'
时,我们基本上是从空到n,所以我们使用上面的表格并看到它以'n'
结束。现在我们得到了banananona的4个字符,所以我们从'n'
开始添加...再次我们使用该表并看到它最终处于状态'na'
,依旧等等......
答案 2 :(得分:0)
转换表中的条目d(q,x)
包含使用字符x
后模式的最长匹配前缀的长度,如果在使用x
之前,最长匹配前缀为{{ 1}}字符长。由于我们使用一个字母,因此不能大于q
,并且由于该模式的长度为q+1
,因此它最多也可以为m
。内部循环为m
,因此在测试任何内容之前,repeat k = k-1 until condition(k)
会递减,因此k
必须比最大可能结果k
开始大1。如果内部循环是k = min(m,q+1) + 1
,则会以while negated_condition(k) { k = k-1; }
开头。
请注意,通过使用Knuth-Morris-Pratt算法的边界表,可以更有效地计算转换表。