KMP算法

懒得讲了,直接背吧(

用途:求字符串pp是否在ss中出现过。

时间复杂度:O(s+p)O(|s|+|p|)

Ps:我们这里字符串下标从00开始计数。

大致思路:

如果是BF算法,那么失配了就算了(

但是如果是KMP算法的话,那么失配了就要跳到fj1f_{j-1}上(代码称为fail)。

如果发现一个字符失配了,那么我们就要把pp移到pp中与失配字符相同的那一位,比如1145141919810就要移到将114514的第一个11919810的第二个1重合。

而这个怎么移呢?答案就是ff数组!

那么ff数组怎么求呢?很简单,我们直接定义fif_i是在ii位以前的离ii最近的并且和pip_i相同的字符的位置

具体证明略(

然后就放个代码吧qwq

#include<bits/stdc++.h>
#define ns "-1"
#define fs(i,x,y,z) for(ll i=x;i<=y;i+=z)
#define ft(i,x,y,z) for(ll i=x;i>=y;i+=z)
#define ll long long
#define ull unsigned long long
#define db double
#define ms(a,b) memset(a,b,sizeof(a))
#define sz(a) sizeof(a)
using namespace std;
const int rw[]={-1,0,1,0,-1,1,-1,1},cl[]={0,1,0,-1,-1,1,1,-1};
const int N=1000001,inf=0x3f3f3f3f;
inline int read(){
	int date=0,w=1;char c=0;
	while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
	while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
	return date*w;
}
string s,p;
int m,n,sa,fail[N];
int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	cin>>s>>p;m=s.size(),n=p.size();
	int j=0;
	fs(i,1,n-1,1){
		while(j>0&&p[i]!=p[j]) j=fail[j-1];
		if(p[i]==p[j]) j++;
		fail[i]=j;	
	}
	j=0;
	fs(i,0,m-1,1){
		while(j>0&&s[i]!=p[j]) j=fail[j-1];
		if(s[i]==p[j]) j++;
		if(j==n){
			cout<<i-n+2<<'\n';
			//j=fail[j];
			j=fail[j-1];
		}	
	}
	fs(i,0,n-1,1) cout<<fail[i]<<' ';
	return 0;
}

Ps:这是洛谷模板的代码。