KMP算法详解

KMP匹配实际上就是在一般匹配的过程中,有没有已经匹配好的了,现场去找又太麻烦所以有了KMP

KMP数组的产生就是自己匹配自己,因为一个字符串能否接续上就是看前缀和后缀有没有重合的部分,例如:EBDAE
这个字符串可以用 KMP 来加快匹配,因为这个字符串有这E这个共同的前缀和后缀,所以有下一个例子:

1
EBDAEBDAE

这个例子中,两个EBDAE叠在了一起,所以在找到第二个EBDAE时,不用重新去找,只需要在第二个E接续上就可以了。

下面是匹配的代码(此时KMP数组为空)

PS: 代码中,i代表着在i个字符范围内,可以直接接续的位置,所以真正的其实点为1,但是当只有1个字符时,最优选就是它自己,所以直接跳过。另外,因为b数组的第一个下标为0,所以里边的i要写成i-1。

1
2
3
4
5
6
7
8
9
// 预处理KMP
int j=0;
for(int i=2;i<=lb;i++){
while(j && b[i-1]!=b[j]){
j=kmp[j];
}
if(b[i-1]==b[j]) j++;
kmp[i]=j;
}

以下是完整代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include<iostream>
#include<string>
#include<cstring>
using namespace std;
string a,b;
int kmp[1000002];
int main(){
cin>>a>>b;
int la=a.length(),lb=b.length();
// 预处理KMP
int j=0;
for(int i=2;i<=lb;i++){
while(j&&b[i-1]!=b[j]){
j=kmp[j];
}
if(b[i-1]==b[j]) j++;
kmp[i]=j;
}
//实践匹配
j=0;
for(int i=1;i<=la+1;i++){
if(j==lb){
j=kmp[j];
cout<<i-lb<<endl;
}
// cout<<a[i-1]<<" "<<b[j]<<endl;
while(j&&a[i-1]!=b[j]){
j=kmp[j];
}
if(a[i-1]==b[j]) j++;
}
for(int i=1;i<=lb;i++){
cout<<kmp[i]<<" ";
}
return 0;
}

KMP算法详解
https://www.insaua.com/articles/kmp-explain/
作者
Eason3Blue
发布于
2023年8月11日
许可协议