注意:以下所有string都是从0开始的
一、功能
求出子串T在字符串S中各次出现的位置
二、性质
最小周期长度:len(S) - next[ len(S) - 1 ];
例如:
“abb”最小周期长度 = 3 – next[2] = 3
“abba”最小周期长度 = 4 – next[3] = 3
三、思路
①next[ i ]:表示第 i 位的最长公共前后缀长度
next的求法:
如果已知next[0] ~ next[i - 1]
令j = next[i – 1],如果s[ i ] = s[ j ],那么j++,next[i] = j ,否则令j = next[ j ],继续之前的操作
若j = 0时依旧无法匹配,那么next[i] = 0
②将S和T合成一个串P=T+'#'+S,对P求next数组
③对于所有的i,满足next[i] = len(T),那么i – 2len(T)便是T在S中出现的初始位置(从0开始)
四、代码
#include<bits/stdc++.h>
using namespace std;
const int MAX=1000005;
string s,t,p;
int lens,lent,lenp;
int nxt[MAX*2];//别忘*2,因为两个串要合并
void kmp_nxt()//求next数组
{
lenp=p.length(), lens=s.length(), lent=t.length();
nxt[0] = 0;
for(int i=1; i<=lenp-1; ++i)
{
int j = nxt[i-1];
while(j>0 && p[i]!=p[j])
j = nxt[j-1];
if(p[i] == p[j]) j++;
nxt[i] = j;
}
}
int main()
{
cin>>s>>t;
p = t+'#'+s;
kmp_nxt();
for(int i=lent+1; i<lenp; ++i)
if(nxt[i] == lent)
printf("%d\n",i-2*lent+1);
for(int i=0; i<=lent-1; ++i)
printf("%d ",nxt[i]);
return 0;
}
/*
ABABABC
ABA
A B A # A B A B A B C
0 0 1 0 1 2 3 2 3 2 0
*/