KMP 字符串匹配 学习笔记
写在前面:
建议大家先去看洛谷P3375这道题,结合题目食用风味更佳
算法的原型:暴力朴素算法(不上代码了因为我懒):将原串与用于匹配的串一位一位的匹配,时间复杂度\(O_(nm)\)
改进方法:使用一个next数组来记录用于匹配的串的这个点之前的串前缀与后缀的最大匹配位数
举个例子:
\(S_1="ABABABABABC"\)
\(S_2="ABABA"\)
那么,我们定义一个指针k指向\(S_2\)当前第k个字符,next[k]就是k之前的串中前缀后缀的最大匹配位数,根据这一点,我们可以将next[0]初始化为-1(或者是将next[1]初始化为0)
这样,我们就可以通过\(O_(m)\)的预处理处理出每一个next,代码如下
void pre(char s[]){
int k=-1,l=strlen(s);
nxt[0]=-1;
for(int i=1;i<l;++i){//这里从1开始是为了匹配后缀
while(k>-1&&s[k+1]!=s[i])k=nxt[k];
if(s[k+1]==s[i])k++;
nxt[i]=k;
}
return;
}
算法核心:利用处理出来的next省去冗余的扫描,让时间复杂度成为线性的\(O_(n+m)\)
具体实现:不好说,我水平还不够,以后补
先上代码,可能比较难以理解,请见谅:
void kmp(char s[],char p[]){
int k=-1;
int l1=strlen(s),l2=strlen(p);
for(int i=0;i<l1;++i){//与预处理相似,预处理其实就是自己与自己匹配
while(k>-1&&p[k+1]!=s[i])k=nxt[k];
if(p[k+1]==s[i])++k;
if(k==l2-1){
printf("%d\n",i-l2+2);
k=nxt[k];
}
}
return;
}