用一个更形象和详细的示例来说明如何构造 next(又称部分匹配表、失配表)。假设我们的模式串是:
pattern = "aabaaac"
我们希望为这个模式串构造一个数组 next[],其中 next[i] 表示 [0…i] 这个子串中“前缀”与“后缀”能够匹配的最长长度。换句话说,next[i] 是“pattern[0…i] 的最长相同前后缀的长度”。
1. 初步理解前后缀
• 前缀:字符串开头到某个中间位置之间的部分(不包含最后一个字符)。
• 后缀:字符串末尾到某个中间位置之间的部分(不包含最前一个字符)。
对 pattern[0…i] 而言:
• 它的「前缀」是 pattern[0…x],x < i。
• 它的「后缀」是 pattern[y…i],y > 0。
举例:对于子串 “aab”,它的前缀可以是 “a”, “aa”;后缀可以是 “b”, “ab”。
如果有某个前缀与后缀完全一样且尽可能长,那么 next[i] 就是它的长度。
2. 步骤概览
1. 初始化:next[0] = 0,因为只有一个字符时,没有可比较的前后缀。
2. 逐一计算:从 i = 1 开始计算 next[i],直到 i = len(pattern) - 1。
3. 使用指针 j:表示已经匹配到的前缀末端位置。
• 初始 j = 0。
• 如果当前字符 pattern[i] 与 pattern[j] 相同,那么 j++,并令 next[i] = j。
• 如果不同,就要回退 j,再试图继续匹配,直到 j == 0 或者找到能匹配的位置。
3. 详细案例:pattern = “aabaaac”
让我们一步步计算各个 i 的 next[i] 值。
3.1 初始化
• next = [0, 0, 0, 0, 0, 0, 0] (与 pattern 长度相同)
• i = 0:子串 “a”,没有前后缀,next[0] = 0。
3.2 i = 1,子串 “aa”
• 当前子串:“aa” (索引 0…1)
• 比较 pattern[1] 与 pattern[j],初始 j = 0:
• pattern[1] = ‘a’, pattern[0] = ‘a’, 相同,则 j++ → j = 1
• 设置 next[1] = j = 1
此时
next = [0, 1, 0, 0, 0, 0, 0]
3.3 i = 2,子串 “aab”
• 当前子串:“aab” (索引 0…2)
• j 的当前值继承自上一次,是 j = 1。
• 比较 pattern[2] 与 pattern[j] = pattern[1]:
• pattern[2] = ‘b’, pattern[1] = ‘a’, 不相同。
• 此时要回退:j = next[j-1] = next[0] = 0.
• 退到 j = 0 后,再比较:pattern[2] 与 pattern[0]:
• ‘b’ != ‘a’, 仍不相同,且 j == 0 就没法再退了。
• 所以 next[2] = 0.
此时
next = [0, 1, 0, 0, 0, 0, 0]
3.4 i = 3,子串 “aaba”
• 当前子串:“aaba” (索引 0…3)
• 上次计算结束 j 已经是 0,所以从 j = 0 开始。
• 比较 pattern[3] 与 pattern[j] → pattern[3] = ‘a’, pattern[0] = ‘a’,相同:
• j++, j=1, next[3] = 1.
此时
next = [0, 1, 0, 1, 0, 0, 0]
标签:子串,剖解,前缀,相同,后缀,pattern,next,算法,KMP
From: https://blog.csdn.net/myprogramc/article/details/145005143