kmp


#include<bits/stdc++.h>
using namespace std;
/*
朴素kmp算法,可简化
const int N=1e6;
const int M=1e6;
int n,m;//m是小的,n是大的
int nxt[M+1],f[N+1];
char s[N+2],p[M+2];
void kmp(){
int j=0;
nxt[1]=0;
for(int i=2;i<=m;i++){//计算next数组,即寻找回溯位置
while(j>0&&p[i]!=p[j+1]){
j=nxt[j];
}
if(p[j+1]==p[i])
++j;
nxt[i]=j;
}
j=0;
for(int i=1;i<=n;i++){
while((j>0&&s[i]!=p[j+1])||j==m){//匹配失败或者到上限就回溯
j=nxt[j];
}
if(p[j+1]==s[i])
++j;
f[i]=j;
}
}
*/
或者把两个字符串拼接,小的在前大的在后,中间用其他字符隔断
const int N=1e6;
const int M=1e6;
int n,m;//m是小的,n是大的
int nxt[N+M+2];
char s[N+2],p[N+M+2];
void kmp(){
n=strlen(s+1);
m=strlen(p+1);
p[m+1]='#';
for(int i=m+2,j=1;i<=n+m+1;j++,i++)
{
p[i]=s[j];
}
int j=0;
nxt[1]=0;
for(int i=2;i<=n+m+1;i++){
while(j&&p[i]!=p[j+1])
{
j=nxt[j];
}
if(p[i]==p[j+1])
j++;
nxt[i]=j;
}
}
int main(){
scanf("%s%s",s+1,p+1);
}
例题1
答案就是n-next[n]
例题2

做法就是将字符串反转之后拼接,中间用#隔断,输出后段字符串里面最大的next就行
接下来是exkmp




const int N=1e6;
int n,z[N+1];//记录拓展kmp结果
char s[N+1];//字符串
void exkmp(){
int L=1,R=0;//维护l到R这个区间,L到R内元素与1到L-R+1中元素相等
z[1]=0;//初始化
for(int i=2;i<=n;i++){
if(i>R)
z[i]=0;//i不在区间内,之后要暴力匹配
else{//i在区间内,不用暴力匹配
int k=i-L+1;//即i元素在1到L-R+1中的相对位置
z[i]=min(z[k],R-i+1);
}
while(i+z[i]<=n&&s[1+z[i]]==s[i+z[i]])//在有效范围内进行匹配
++z[i];
if(i+z[i]-1>R)
L=i,R=i+z[i]-1;//更新RL区间
}
}


1078

被折叠的 条评论
为什么被折叠?



