KMP字符串匹配算法 整理
KMP 整理
KMP 的作用
KMP 算法的主要作用是求出一个字符串(模式串)是否为另一个字符串(主串)的子串,并同时求出它出现的位置,也即字符串匹配问题。
算法解析
暴力
先说暴力算法:
-
从头开始枚举模式串位置的起点,然后遍历从起点往后
个字符,检查它是否与模式串完全相同。 -
复杂度为
, 遍历起点,对于每个起点用 检查是否与模式串相同
我们发现时间复杂度奇高,于是便有三位 dalao (Knuth,Morris,Pratt) 共同发明了 KMP 算法,他的核心思想就是利用已知的数据,利用好,不往回头走,从而做到
KMP
KMP 算法思路:
我们设当前比对主串(str1)的下标是 ++
,开始比较下一个字符 ;若
举个栗子:
第一次匹配
模式串: ABABC
主串: ABABABCAB
这时我们发现模式串的C与主串的A不匹配,但是由于我们已经知道了主串的前5个字符,发现模式串的[1,2]串和[3,4]串相同,所以我们直接将模式串跳过前面的[1,2]串AB再进行比较。
第二次匹配
模式串: ABABC
主串: ABABABCAB
这时我们发现模式串和主串匹配了,于是说明模式串为主串的字串。
那我们如何知道该跳过夺少字符呢?这时候就要用到
next 数组
那我们如何知道
模式串: A B A B C
next数组: 0 0 1 2 0
那 i = 2, j = 0
开始枚举。由于我们要用递推的算法来计算,于是我们比较 str[i]
和 str[j + 1]
,若两者相等,则说明当前最长前后缀其实是上一个最长前后缀个添加一个相同的字符,此时前后缀依然相等,于是我们执行 j++; next[i] = j;
;而如果两者不同,我们就反复执行 j = next[j];
,直到 str[i]==str[j + 1]
或者是 j <= 0
,因为此时我们就已经找到了最长相同前后缀或者当前字串根本不存在最长相同前后缀。
实现流程:
(1)设 str[i]
和 str[j + 1]
,若相等,那么执行 j++; next[i] = j;
(2)若不相等,j = next[j];
直到 str[i]==str[j + 1]
或 j <= 0
为止。
Code:
#include<bits/stdc++.h>
using namespace std;
string str1, str2;
const int N = 1e6 + 10;
int nxt[N];
int main() {
cin >> str1 >> str2;
for(int i = str1.size(); i >= 1; i--) {
str1[i] = str1[i - 1];
}
for(int i = str2.size(); i >= 1; i--) {
str2[i] = str2[i - 1];
}
for(int i = 2, j = 0; i <= str2.size(); i++) {
while(j && str2[j + 1] != str2[i]) {
j = nxt[j];
}
if(str2[j + 1] == str2[i]) j++;
nxt[i] = j;
}
for(int i = 1, j = 0; i <= str1.size(); i++) {
while(j && str2[j + 1] != str1[i]) {
j = nxt[j];
}
if(str2[j + 1] == str1[i]) j++;
if(j >= str2.size()) {
cout << i - j + 1 << "\n";
j = nxt[j];
}
}
for(int i = 1; i <= str2.size(); i++) cout << nxt[i] << " ";
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)