KMP 字符串匹配 学习笔记
KMP 算法是用来判断一个文本串
定义
以下所有解释,字符串下标都以
朴素算法
显然,判断上述问题需要两层循环,第一层枚举文本串
显然,这种算法的时间复杂度为
我们发现每次匹配失败都会将模式串向后移动一位继续与文本串进行匹配,这样做效率太慢了,而 KMP 算法也是对这一点进行了优化。
KMP
原理
举例:
a: abcabxabdd
b: abcabd
^
我们在第一轮匹配中,发现
即:
a: abcadxabdd
b: abcabd
这样效率是很慢的。
我们发现在第一轮匹配中,abcab
,这都是匹配上了的,我们发现这一个子串中有一个公共前后缀 ab
,那么我们下一次挪动 ab
对准 ab
,那么我们就会发现我们节省了很多没有必要的挪动,这样一来我们就可以直接从第三个字母 c
开始匹配。
即:
a: abcab xabdd
b: abcab d
^^ ^^
挪动为:
a: abcab xabdd
b: ab cabd
^^
这样我们只需要从再匹配后面的 cabd
就好了。节省了大量的时间。
那么我们就需要找到匹配串前 abcab
的 ab
),为什么要找最长的呢?因为这样挪动的越多,越节省时间。
步骤一:求解 nxt 数组
知道了原理以后,我们需要求解每个
我们记
我们使用两个指针
做法:
我们每次判断
对于做法的解释:
由于我们定义了
举例:
我们现在对 abcdabca
这个字符串进行求解
p: j i
b: a b c d a b c a
nxt: 0
根据以上说的做法,我们容易得出:
p: j i
b: a b c d a b c a
nxt: 0 0 0 0
此时
我们继续这样做,易得:
p: j i
b: a b c d a b c a
nxt: 0 0 0 0 1 2 3
那么现在我们现在
p: j i
b: a b c d a b c a
nxt: 0 0 0 0 1 2 3 1
那么我们整个求解过程就结束了。
代码实现
时间复杂度
j = 0;
for (int i = 2;i <= lena;i++){
while (j && b[i] != b[j + 1]){
j = nxt[j];
}
if (b[i] == b[j + 1]){
j++;
}
nxt[i] = j;
}
步骤二:开始匹配
我们仍然用到两个指针
不过与上一个部分不同的是,这里的
匹配与上一个部分也很类似。
若
否则,原理
这一部分说过了),就是对朴素算法的优化。
代码实现
时间复杂度
j = 0;
for (int i = 1;i <= lena;i++){
while (j && a[i] != b[j + 1]){
j = nxt[j];
}
if (a[i] == b[j + 1]){
j++;
}
if (j == lenb){
cout << "Yes";
return 0;
}
}
总结
KMP 就是对朴素算法匹配字符串的优化,通过求最长公共前后缀进行灵活的挪动。
总复杂度
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效