KMP算法(史上最清晰版本,每一步思路都仔细剖解)

用一个更形象和详细的示例来说明如何构造 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]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值