KMP 模板(修订,更易懂)
KMP 模板(修订,更易懂)
之前一篇博客简单介绍了KMP的原理,但当时写的模板两个字符串数组都是从下标为0开始的,逻辑有些混乱.
这次修改了x,y下标从1开始,感觉更加自然.
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6+5;
const int M = 1e4+5;
int xlen,ylen;
int pre[M];
char x[M];
char y[N];
// x 是模式串,y 是文本串,均从1开始
void read_string(){
scanf("%d%d",&xlen,&ylen);
scanf("%s",x+1);
scanf("%s",y+1);
}
// pre[i]: x串的长度为i的子串的公共前后缀长度
void get_pre(){
pre[0] = -1;
pre[1] = 0;
for(int i = 2; i <= xlen; ++i){
if(x[i] == x[pre[i-1]+1]){
pre[i] = pre[i-1] + 1;
}else{
int ptr = pre[i-1] + 1;
while(ptr >= 1 && x[ptr] != x[i]){
ptr = pre[ptr-1] + 1;
}
pre[i] = ptr;
}
}
}
int kmp_match(int ans[]){
int cnt = 0;
int xptr = 1,yptr = 1;
while(xptr <= xlen && yptr <= ylen){
if(xptr == 0 || x[xptr] == y[yptr]){
++xptr;
++yptr;
}else{
xptr = pre[xptr-1] + 1;
}
if(xptr == xlen + 1){
// 注意此时x和y都已经向后移位了
ans[++cnt] = yptr - xptr + 1;
xptr = pre[xptr-1] + 1;
}
}
return cnt;
}
int main(){
read_string();
get_pre();
for(int i = 0; i <= xlen; i++){
printf("pre[%d] = %d\n",i,pre[i]);
}
int ans[10];
int cnt = kmp_match(ans);
for(int i = 1; i <= cnt; i++){
printf("%d\n",ans[i]);
}
system("pause");
return 0;
}
---- suffer now and live the rest of your life as a champion ----