KMP&拓展KMP

KMP算法

说明#

KMP算法是一种比较高效的字符串匹配算法,可以在线性时间内求出一个串在另一个串的所有匹配位置。

解析#

详解KMP

设模板串是 patternnext[i]=max{k|pattern[0...k1]=pattern[ik+1...i]}, next[] 可以通过动态规划求解。

板子#

next数组存在的意义:

A 串匹配到 iB 串匹配到 j时, 如果发现失配,可以直接令 j=next[i] 然后继续匹配, ( next[i] 将记录如果 B 串匹配到 Ai 位置,前面有多少是已经匹配了的。)

next 数组的求法

算法流程

  1. 初始化 next[1]=j=0 ,假设 next[1...i1] 已经求出,下面求解 next[i]
  2. 不断尝试扩展长度 j, 如果扩展失败(下一个字符不相等),令 j 变为 next[j], 直至 j=0(应该从头开始匹配)
  3. 如果扩展成功,匹配长度 j 就增加 1, next[i] 的值就是 j
Copy
inline void calc_next() { next[1] = 0; for (int i = 2, j = 0; i <= n; ++ i) { while (j > 0 && a[i] != a[j + 1]) j = next[j]; if (a[i] == a[j + 1]) j ++; next[i] = j; } }

我们用f数组记录每个位置能匹配的个数,基于 next 数组,我们能在 O(n+m) 的时间处理结果

Copy
inline void calc_f() { for (int i = 1, j = 0; i <= m; ++ i) { while (j > 0 && (j == n || b[i] != a[j + 1])) j = next[j]; if (b[i] == a[j + 1]) j ++; f[i] = j; if (f[i] == n) {/* the first time */} } }

拓展KMP算法

说明#

在线性复杂度内求出一个串对于另一个串的每个后缀的最长公共前缀

解析#

假设两个串是 sp, 要求 p 的每个 s 的后缀的最长公共前缀.

我们可以先求出 p 与它自己的每个后缀的最长公共前缀(假设为 A)。类似KMP的思想,假设我们现在要计算 p 的第 i 个字符开头的后缀,而我们已经得到了 A[1...i1], 我们可以找到以前的一个 k 使得 k+A[k]1 最大(就是匹配到的范围最大),我们可以得知 p[1...A[k]]=p[k...k+A[k]1], 于是可以得到 p[i...k+A[k]1]=p[ik+1...A[k]],即我们可以利用 A[ij+1] 的信息。

分两种情况讨论,如果 i+A[ik+1]1k+A[k]1小,则 A[k]=A[ik+1] ,否则暴力扫一次。计算 ps 的后缀的最长公共前缀也是类似的方法,可以证明复杂度是线性的。

板子#

(未精简版本)

输入:求 a 关于 b 的后缀的最长公共前缀, Next 记录 a关于自己每个后缀的最长公共前缀, ret 记录 a 关于 b 的后缀的最长公共前缀

Copy
void ExtendedKMP(char *a, char *b, int M, int N, int *Next, int *ret) { int i, j, k; for (j = 0; 1 + j < M && a[j] == a[1 + j]; ++ j); Next[1] = j; k = 1; for (i = 2; i < M; ++ i) { int Len = k + Next[k], L = Next[i - k]; if (L < Len - i) { Next[i] = L; } else { for (j = max(0, Len - i); i + j < M && a[j] == a[i + j]; ++ j); Next[i] = j; k = i; } } for (j = 0; j < N && j < M && a[j] == b[j]; ++ j); ret[0] = j; k = 0; for (i = 1; i < N; ++ i) { int Len = k + ret[k], L = Next[i - k]; if (L < Len - i) { ret[i] = L; } else { for (j = max(0, Len - i); j < M && i + j < N && a[j] == b[i + j]; ++ j); ret[i] = j; k = i; } } }
posted @   AlessandroChen  阅读(604)  评论(0编辑  收藏  举报
编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示
CONTENTS