KMP的重点在于如何构造next数组,也就是求出子串自己匹配自己,遍历字符串,
(
s
[
0
]
,
s
[
i
]
)
=
(
s
[
n
−
1
−
i
]
,
s
[
n
−
1
]
)
(s[0],s[i])=(s[n-1-i],s[n-1])
(s[0],s[i])=(s[n−1−i],s[n−1])
对于每个下标
i
i
i,求出此时最大相等前后缀长度时,前缀的下标
n
e
[
i
]
ne[i]
ne[i]
#include<iostream>#include<cstring>usingnamespace std;constint N =1e6+10;int ne[N];char p[N], s[N];intmain(){int n , m ;
cin>>s>>p;
n =strlen(p);
m =strlen(s);
ne[0]=-1;//ne数组表示为最小的相等前后缀长度时,前缀的下标(如果前后缀不相等我就记这里是 -1)//(next数组)模式串前后缀相等的种数for(int i =1, j =-1; i < n ; i++){while(j !=-1&& p[i]!= p[j+1]){
j = ne[j];//匹配失败,折半退回继续匹配}if(p[i]== p[j+1]) j++;//匹配成功+1继续匹配
ne[i]= j;//记录这个从模式串的头到位置i前缀后缀相等的前缀下标}//主串与模式串的匹配for(int i =0, j =-1; i < m ; i++){//kmp开始while(j !=-1&& s[i]!= p[j+1]){//主串模式串匹配失败,折半退回继续查找
j = ne[j];}if(s[i]== p[j+1]) j++;//匹配成功继续查找if(j == n -1){//模式串到头,输出位置,因为下标从0 开始所以在这里加个1
cout<<i - j+1<<endl;
j = ne[j];//也可能是子串套子串,所以退回一格继续查找}}for(int i =0; i < n ; i++){
cout<<ne[i]+1<<' ';//因为是子串查找要的是长度不是下标,所以这里也普遍加1}return0;}```