KMP算法与Z算法的关系

时间:2013-08-29 21:34:03

标签: string algorithm search

KMPZ算法是众所周知的字符串搜索算法,

KMP算法处理通过KMP失败函数查找模式,该函数定义为(pat是搜索模式)

  

lps [i] = pat [0..i]的最长正确前缀,它也是pat [0..i]的后缀。

例如,对于string "abcab",它将是[0, 0, 0, 1, 2]

其中Z算法使用z函数,该函数定义为:

  

给定长度为n的字符串S,Z算法产生一个数组Z,其中Z [i]是从pat [i]开始的最长子字符串的长度,也是pat的前缀。

现在问题是我们可以通过使用Z算法来实现KMP函数吗? 我要搜索的是lps数组中的一些修改,这些修改会导致与Z[i]数组相同的结果。

3 个答案:

答案 0 :(得分:3)

注意:算法错误

for i in range(0, len(s)):
    if lps[i] != 0:
        Z[i - lps[i] + 1] = lps[i]

之后在Z[i]中将是后缀的最大长度,从位置i开始,也是字符串的前缀。

修改

正如nikhil_vyas所说,提出的算法无法解决您的问题。它实际上做的是用最长的后缀和其他一些部分填充Z数组。这种不完整的数组基本上可以帮助你解决几个“找到字符串中最长的东西”的问题,但它没有回答你的问题。

重建具有Z数组的lps数组的最简单方法是构建字符串,对应于lps数组,然后构建Z数组为那个字符串。但我不确定它是否适合您对“lps数组中的某些修改”的定义。

答案 1 :(得分:1)

我认为这样做会。

Z = [0] * len(lps) # initialize most to 0

iterator = enumerate(zip(lps, lps[1:]), start=1)
for i, (prev, cur) in iterator: # step through adjacent pairs

    if cur <= prev: # suffix stopped growing

        Z[i - prev] = prev # Mark this suffix at its beginning.

# end of loop

# Ending the string is also a way to stop growing the suffix.
if cur > 0: # if we were still growing a suffix

    # At end of loop, cur is the new prev, and i+1 is the new i.
    # (i == len(lps) - 1, cur == lps[-1])
    Z[i+1 - cur] = cur

样品:

lps = [0,0,0,1,2] #=> [0,0,0,2,0]
lps = [0,0,1,2,1,2] #=> [0,0,2,0,2,0]

答案 2 :(得分:0)

Mikhail Melnik的解决方案可能无法为像“aaaaa”这样的字符串中的所有索引计算Z,我们需要额外的迭代来填充在第一次迭代中留空的索引。

for i in range(0, len(s)):
    Z[i - lps[i] + 1] = lps[i]
for i in range(0, len(s)):
    Z[i] = max(Z[i], Z[i - 1] - 1)                     `