KMP
模板:
int kmp[MAXN]; //kmp[i]的基本定义是:在第1-第i位中真前缀与真后缀相同的部分最长是多长
char a[MAXN],b[MAXN]; //a是文本串,b是模板串,kmp数组是b的next数组 (注意:数组从1开始)
int kmpp(){
int la,lb,j=0;//j可以看做表示当前已经匹配完的模式串的最后一位的位置
la=strlen(a+1);
lb=strlen(b+1);
for(int i=2;i<=lb;i++){ //自己匹配自己
while(j&&b[i]!=b[j+1])j=kmp[j]; //找到最长的前后缀重叠长度
if(b[j+1]==b[i])j++;
kmp[i]=j;
}
j=0;
int res=0;
for(int i=1;i<=la;i++){
while(j>0&&b[j+1]!=a[i])j=kmp[j]; //如果不匹配,则将利用kmp数组往回跳
if(b[j+1]==a[i]) j++;
if(j==lb){
//cout<<i-lb+1<<endl;
j=kmp[j];
res++;
}
}
return res;
}
主要是next数组:
next[i] i是前i个字符中,最长的,相同的前后缀,的长度
比如:对于B字符串asdask
它是next数组为:000120
asdask
000120
其中,当i=5时对应第二个s的位置,这时前i个字符为asdas,它的最长的相同的前后缀的长度为2,也就是as。
如要比较A字符串asdasdask
当到第二个s的时候由于下一个字母是d而B字符串中下一个字母是k,于是根据next数组跳到B字符串的第一个s处发现B字符串下一个字母为d,与A字符串下一个字母相同,于是继续。
扩展KMP
模板:
int nxt[N],extend[N];
string s,t;
void getnxt(){
nxt[0]=t.size();//nxt[0]一定是T的长度
int now=0;
while(t[now]==t[1+now]&&now+1<(int)t.size())now++;//这就是从1开始暴力
nxt[1]=now;
int p0=1;
for(int i=2;i<(int)t.size();i++){
if(i+nxt[i-p0]<nxt[p0]+p0)nxt[i]=nxt[i-p0];//第一种情况
else{
//第二种情况
int now=nxt[p0]+p0-i;
now=max(now,0);//这里是为了防止i>p的情况
while(t[now]==t[i+now]&&i+now<(int)t.size())now++;//暴力
nxt[i]=now;
p0=i;//更新p0
}
}
}
void exkmp(){
getnxt();
int now=0;
while(s[now]==t[now]&now<min((int)s.size(),(int)t.size()))now++;//暴力
extend[0]=now;
int p0=0;
for(int i=1;i<(int)s.size();i++){
if(i+nxt[i-p0]<extend[p0]+p0)extend[i]=nxt[i-p0];//第一种情况
else{
//第二种情况
int now=extend[p0]+p0-i;
now=max(now,0);//这里是为了防止i>p的情况
while(t[now]==s[i+now]&&now<(int)t.size()&&now+i<(int)s.size())now++;
extend[i]=now;
p0=i;//更新p0
}
}
}
有两个字符串S,T,要求输出T与S的每一个后缀的最长公共前缀
输入: S: aaaabaa T: aaaaa
输出: 5 4 3 2 1 (T的nxt数组:T的每一个后缀与T的最长公共前缀长度) 4 3 2 1 0 2 1 (extend数组:S的每一个后缀与T的最长公共前缀长度)
AC自动机
来源:CSDN
作者:weixin_44162741
链接:https://blog.csdn.net/weixin_44162741/article/details/104591271