KMP
QUESTION:
有一个文本串S,和一个模式串P,现在要查找P在S中的位置,怎么查找呢?
ANSWER:
KMP
step1:(真)前缀&(真)后缀
char | pre | suc | pre suc |
---|---|---|---|
abc | a,ab | c,bc | |
abcba | a,ab,abc,abcb | a,ba,cba,bcba | a |
ababa | a,ab,aba,abab | a,ba,aba,baba | a,aba |
abcab | a,ab,abc,abca | b,ab,cab,bcab | ab |
设 为 ~ 的 中最长元素的长度
P | a | b | a | b | a | b | c | a |
---|---|---|---|---|---|---|---|---|
nxt | -1 | 0 | 0 | 1 | 2 | 3 | 4 | 0 |
好了,解释清楚这个表是什么之后,我们再来看如何使用这个表来加速字符串的查找
e.g.
S="ababababca" P="abababca"
如果在 j 处字符不匹配,那么由于前边所说的 字符串 的性质,
~ ~ (伪代码)
这是因为主字符串在 i 位失配,也就意味着
~ ~ (伪代码)
在这个例子中就是
~ ~ (伪代码)
的最长元素为 ,长度为 。
所以就可以断言,(a)图中两个灰色部分是相同的,即长度为 的后缀与前缀相同。
这样一来,我们就可以将灰色字符段的比较省略掉。
具体的做法是:(即变为(b)图)
i=i; j=nxt[j];
具体函数:
int KMP() { int i = 0; int j = 0; while(i < S.size() && j < P.size()) { if (j == -1 || S[i] == P[j]) i++; j++; } else { j = nxt[j]; } } if (j == P.size()) return i - j; else return -1; }
但是怎么求nxt?
SO EASY
求 的过程完全可以看成字符串匹配的过程,即
newS=P; newP=P.pre;//P的前缀皆可
一旦字符串匹配成功,那么当前的 值就是 匹配 。
具体来说,就是从的第一位(注意,不包括第0位)开始对自身进行匹配运算。
void getNxt() { nxt[0] = -1; int i = 0, j = -1; while (i < P.size()) { if (j == -1 || P[i] == P[j]) { i++; j++; nxt[i] = j; } else j = nxt[j]; } }
D.E.Knuth
J.H.Morris
V.R.Pratt
三人联手打造KMP
KMP解决字符串匹配问题
(n为原串长度,m为匹配串长度)
蛮力算法:O(nm)
KMP:O(n+m)
若在匹配中在图中蓝色位置失配
则匹配串要右移(假设原串与蓝框不动)
因为目标是让匹配串全部匹配,所以右移后让匹配串全部匹配的必要条件是图中绿框串相等(不相等的话直接GG)
为避免回溯,绿框大小尽可能大(但不碰蓝框),即右移位移少(保险)
理解如何求出
顺次扫描模式串P中每个元素,求出
当遍历到时,至均已经求出
如图求出即可(为常数,图中相同颜色的矩形和相同的符号分别代表相同的子串和相同的字符)
本文来自博客园,作者:ShaoJia,版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义