【问题标题】:How to use KMP failure function to determine minimum length repeated substring?如何使用 KMP 失败函数确定最小长度重复子串?
【发布时间】:2015-10-13 14:36:15
【问题描述】:

我想使用 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),否则为给定字符串的长度。

我了解什么是故障函数以及它如何用于在文本中查找模式,但我很难理解这种技术的正确性证明。

【问题讨论】:

  • 我投票结束这个问题,因为它不是一个编程问题。
  • 如果这个问题不适合堆栈溢出,你能建议我在哪里问这个问题以获得好的答案吗?
  • 这适用于 SO,因为它询问算法是如何工作的。这是算法标签的中心点。

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


【解决方案1】:

请记住,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.. 现在如果它是一个重复的字符串 than ,它的最小长度将是 2. (6(string length) – 4) , Now

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

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

【讨论】:

  • "所以你必须检查是否 len % (len - last_in_pi) == 0。如果是,那么 len - last_in_pi 是最短重复字符串(句点字符串)的长度。 " 但是为什么这行得通呢?我用谷歌搜索了这个过程,发现它被称为布斯算法wiki@IVlad
【解决方案2】:

问题

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 后缀。将 previous Ly 原始字符串 S 中的字符数附加到它。这不会超过字符串长度,因为 (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是不存在的。

【讨论】:

    【解决方案3】:
    • 假设您有一个大小为 n 的字符串 s,看起来像 s = x1x2x3...x[n-2]x[n-1]x[n]
    • 假设 s 的最大公共前缀/后缀长度为 len
    • 那么它的周期是 p = (n - len), iff 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]
      • ...

    【讨论】:

      猜你喜欢
      • 2020-10-03
      • 2017-10-18
      • 2014-03-22
      • 2022-06-10
      • 2015-06-16
      • 2016-11-17
      • 1970-01-01
      • 2020-03-22
      • 1970-01-01
      相关资源
      最近更新 更多