https://www.luogu.com.cn/problem/P3375
思路:
以前看着有一点迷糊。现在看看kmp的核心就是一个处理最大公共前后缀,匹配失败的时候直接优化。定义D[i]:0~i的一共i+1个字母的最大公共前后缀。处理的p和t匹配的时候直接用d就能优化,预处理出d[i]就是错开一位让p串和自身匹配,当然由于匹配到i位置,前i-1的D[0~i-1]都处理好了,所以这个匹配也是直接匹配失败跳转的。
#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<cstdio>
#include<algorithm>
#define debug(a) cout<<#a<<"="<<a<<endl;
using namespace std;
const int maxn=1e6+100;
typedef int LL;
inline LL read(){LL x=0,f=1;char ch=getchar(); while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
return x*f;}
LL d[maxn];
char s1[maxn],s2[maxn];
/*d[i]:p[0]~p[i]共计i+1个字符的最大公共前后缀*/
void pre(const char s[],LL np){
for(LL i=0;i<=np+10;i++) d[i]=0;
LL i=1;LL j=0;
while(i<np){
if(s[i]==s[j]) d[i++]=++j;
else{
if(j>0) j=d[j-1];
else i++;
}
}
}
void kmp(const char t[],const char p[]){
LL nt=strlen(t);
LL np=strlen(p);///预处理border
pre(p,np);
LL i=0;LL j=0;
while(i<nt){
if(p[j]==t[i]){
i++;j++;
if(j==np){
printf("%d\n",i-j+1);
j=d[np-1];
}
}
else{
if(j>0) j=d[j-1];
else i++;
}
}
}
int main(void){
scanf("%s%s",s1,s2);
kmp(s1,s2);
LL sn=strlen(s2);
for(LL i=0;i<sn;i++) printf("%d ",d[i]);
return 0;
}