如何使用KMP失败函数来确定重复子串的最小长度?

时间:2015-07-23 10:33:03

标签: algorithm pattern-matching knuth-morris-pratt

我想使用KMP算法解决UVA 10298 -"Power Strings"问题。在this博客中,显示了一种技术如何使用失败函数来计算重复子串的最小长度。技术如下:

  1. 为给定字符串计算前缀后缀表pi[ ]
  2. len为字符串长度,last_in_pi为存储在pi表的最后一个索引处的值。
  3. 检查len % (len - last_in_pi) == 0是否为真。如果为真,则最小长度重复子字符串的长度为(len - last_in_pi),否则为给定字符串的长度。
  4. 我理解什么是失败函数以及如何使用它来查找文本中的模式,但我很难理解这种技术的正确性证据。

3 个答案:

答案 0 :(得分:4)

请记住,Pi[i]被定义为your_string的最长前缀(长度),它是子串your_string[0 ... i]的正确后缀(因此不是整个字符串)。

您链接到的博客文章中有一个示例:

    0 1 2 3 4 5
S : a b a b a b
Pi: 0 0 1 2 3 4

我们在哪里:

  

a b a

     

a b a b

等。我希望这清楚地表明Pi(前缀函数/表)的作用。

现在,博客说:

  

前缀表的最后一个值= 4 ..   现在如果它是一个重复的字符串,它的最小长度将是2.(6(字符串长度) - 4),现在

所以你必须检查len % (len - last_in_pi) == 0。如果是,则len - last_in_pi是最短重复字符串(句点字符串)的长度。

这是有效的,因为如果您以任意方式旋转len(period)个位置的字符串,它将匹配自身。 len - last_in_pi告诉您需要旋转多少。

答案 1 :(得分:0)

问题

S(长度为Ls)是给定的字符串。 M(长度为Lm)是S的最大后缀,也是S的前缀。我们必须证明Ls - LmS的最短时间的长度。

通过矛盾证明

我们假设存在一个时期Y,其长度为Ly < Ls - Lm(即比上述技术给出的时期短)。

要注意的重要属性是MY的适当前缀,反之亦然,具体取决于它们的长度。我们可以将其表示为M = n*Y + Z,其中n >= 0Z是附加部分,Lz < LyZ会重复,因此Y形成了Y的前缀。让Y = Z + W

考虑后缀M。在原始字符串S中附加上一个 Ly个字符。这不会超过字符串长度,因为(Ly < Ls - Lm)。新后缀为(n + 1)*Y + Z

请考虑M前缀。现在,在原始字符串S中附加 next Ly个字符。此处的新前缀为

M + (next Ly characters from S)
- > n*Y + Z + (Ly characters)  
- > n*Y + Z + (Ly - Lz characters) + (Lz characters)  
- > n*Y + (Z + W) + (Z)  
{The `Ly - Lz` characters should be `W` because `Z` and these together form `Y`; The last Lz characters are actually the the first Lz characters of Y which is nothing but Z}  

- > (n + 1)*Y + Z  

现在,我们有一个正确的后缀S,它也是一个前缀,并且大于M。但是我们开始说M是最长的适当后缀,它也是前缀。因此,这是一个矛盾,意味着这样的Y不存在。

答案 2 :(得分:0)

  • 假设您有一个大小为n的字符串s,看起来像s = x1x2x3 ... x [n-2] x [n-1] x [n]
  • 假设s的最大公共前缀/后缀长度为len
  • 然后它的周期是p =(n-len),当n%p == 0
  • 归纳法:
    • 表示前缀= s [1 ... len],后缀= s [p + 1 ... n]
    • 然后我们有前缀[1 ... p] ==后缀[1 ... p] == s [p + 1 ... 2p]
    • 因为s [p + 1 ... 2p] ==前缀[p + 1 ... 2p],所以后缀[1 ... p] ==后缀[p + 1 ... 2p]
    • 递归后缀[p + 1 ... 2p] == s [2p + 1 ... 3p] ==前缀[2p + 1 ... 3p]
    • ...