扩展KMP
为了叙述方便,设S(i)S(i)为串SS从开始的后缀
扩展KMP可以在线性时间内求出对于一个文本串SS的每一个后缀与模板串TT的最长公共前缀(LCP),我们设其为。
假设我们已经知道了T(i)T(i)与TT的LCP,设为,考虑怎么求exiexi。
假设当前ex1∼exi−1ex1∼exi−1,都已求出,设其中最大的exkexk为eded,对应的kk为,那么分两种情况讨论:
1. nexti−st+1<ed−st+1nexti−st+1<ed−st+1;设w=nexti−st+1w=nexti−st+1,首先因为Sst..ed=T1..ed−st+1Sst..ed=T1..ed−st+1,那么S(i)=T(i−st+1)S(i)=T(i−st+1)的LCP为ww,又因为,得到exi=wexi=w。
2. nexti−st+1≥ed−st+1nexti−st+1≥ed−st+1;同理,exiexi至少为ed−i+1ed−i+1,但还可能更多,暴力拓展eded即可。
其实nextinexti的求法也是类似的。
考虑每拓展一次eded至少+1+1,所以时间复杂度是O(n)O(n)的。
实现中有个细节就是eded要和i−1i−1取一个maxmax。
代码:
void ex_kmp(char s[],char t[],int nxt[],int ex[])
{
int st=1,ed=0;
nxt[1]=n;
for(int i=2;i<=n;i++)
{
if(nxt[i-st+1]<ed-i+1) {nxt[i]=nxt[i-st+1];continue;}
ed=max(i-1,ed);
for(int j=ed-i+1;ed<n&&t[ed+1]==t[j+1];ed++,j++);
st=i;nxt[i]=ed-i+1;
}
st=1;ed=0;
for(int i=1;i<=n;i++)
{
if(nxt[i-st+1]<ed-i+1) {ex[i]=nxt[i-st+1];continue;}
ed=max(i-1,ed);
for(int j=ed-i+1;ed<n&&s[ed+1]==t[j+1];ed++,j++);
st=i;ex[i]=ed-i+1;
}
}