我想使用KMP算法解决UVA 10298 -"Power Strings"问题。在this博客中,显示了一种技术如何使用失败函数来计算重复子串的最小长度。技术如下:
pi[ ]
。len
为字符串长度,last_in_pi
为存储在pi
表的最后一个索引处的值。len % (len - last_in_pi) == 0
是否为真。如果为真,则最小长度重复子字符串的长度为(len - last_in_pi)
,否则为给定字符串的长度。我理解什么是失败函数以及如何使用它来查找文本中的模式,但我很难理解这种技术的正确性证据。
答案 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 - Lm
是S
的最短时间的长度。
我们假设存在一个时期Y
,其长度为Ly < Ls - Lm
(即比上述技术给出的时期短)。
要注意的重要属性是M
是Y
的适当前缀,反之亦然,具体取决于它们的长度。我们可以将其表示为M = n*Y + Z
,其中n >= 0
和Z
是附加部分,Lz < Ly
。 Z
会重复,因此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)