(c4)KMP算法:构造next[]表
KMP 算法:构造 next[] 表
看完你能亲手推演next[]表的每一步递推,并写出正确处理边界的匹配代码
按 空格/→ 演示下一步
全部页面点击任意一页,跳回舞台从这页播放
KMP 算法:构造 next[] 表
看完你能亲手推演next[]表的每一步递推,并写出正确处理边界的匹配代码
暴力匹配的痛点
从左往右看:主串指针 i 一路前进,一旦失配就大幅回退,前面比对过的字符全部白比。
next[] 的定义
上一页看到暴力匹配会反复回退主串。KMP 的解法是让模式串自己记住:失配时该从哪里继续。这份备忘录就是 next[] 表,先给它一个严格定义。
读到读不懂处先查索引,索引告诉你从哪页接着读,而不是从头翻
两种情形的分界
从左往右看:求 next[j] 时先查一条边是否相等,相等走短路,不等走回退长路。
失配时的递归回退
失配时沿 next 表逐级回退 k,每一步都在找更短的相等前后缀。
手工推演示例
以模式串 ABABC 为例,从左到右逐位递推 next[],每步只看前一位的比较结果。
构造 next[] 的代码
把前面两页的递推与回退浓缩成一个可运行的构造函数。
while 是失配回退分支(k=nxt[k-1]),if 是匹配延长分支(k+=1),与手工推演的两情形一一对应。
代码逐步走查
用模式串 ababa 单步执行代码,逐项核对 next[] 的每个值。
双指针的摊还分析
追踪 i 与 k 的总移动次数:i 只增不减,k 虽会回退但每次回退都由 i 的前进「付费」,总代价 O(m)。
边界情形辨析
next[] 最易错的是两个极端:无公共前后缀时取什么、全同字符时为何一路递增。边界值最能检验你是否真懂定义。
- 例:"abcad",比较 b 与 c 处失配
- 前后缀无交集,最长相等前后缀长为 0
- next[j] 只能取 0,j 回到开头重比
- 例:"aaaaa",任何位置失配
- 每个前缀都等于后缀,长度取满 j
- next[j] = j-1,一路线性递增
自测:算一张 next 表
模式串 "ababab",next[1]=0(下标从 1 开始),正确的 next[] 表是?
要点收束
- ✓next[j] 的本质:真前缀与真后缀的最长相等长度
- ✓递推只用两种情形:相等就延伸,失配就回退
- ✓回退是递归的,但被 next[] 链条天然有序化
- ✓摊还分析保证:双指针均摊各走 O(n) 步
- ✓边界优先想 j=0 与 j=1:递推的锚点
课后思考
先合上笔记自己想十分钟,再对照参考答案,看思路是否对得上。
参考答案顺着定义想:next[j] 记录的就是「最长的相等真前缀后缀」。回退到 next[j] 等于换一个更短的候选前缀,且所有比它长的都已排除,故不漏。
参考答案思路:最长的那个也是个数之一,可在求最长时顺带累加链上所有匹配长度。想想能否 O(1) 递推,还是必须沿回退链逐个数?
参考答案相等前后缀的定义依赖字符逐一相等,通配符打破了这一点。可把「相等」改成「可匹配」再重推构造;想想传递性还在不在?