扩展KMP
为了叙述方便,设
S(i)
S
(
i
)
为串
S
S
从开始的后缀
扩展KMP可以在线性时间内求出对于一个文本串
S
S
的每一个后缀与模板串
T
T
的最长公共前缀(LCP),我们设其为。
假设我们已经知道了
T(i)
T
(
i
)
与
T
T
的LCP,设为,考虑怎么求
exi
e
x
i
。
假设当前
ex1∼exi−1
e
x
1
∼
e
x
i
−
1
,都已求出,设其中最大的
exk
e
x
k
为
ed
e
d
,对应的
k
k
为,那么分两种情况讨论:
1.
nexti−st+1<ed−st+1
n
e
x
t
i
−
s
t
+
1
<
e
d
−
s
t
+
1
;设
w=nexti−st+1
w
=
n
e
x
t
i
−
s
t
+
1
,首先因为
Sst..ed=T1..ed−st+1
S
s
t
.
.
e
d
=
T
1..
e
d
−
s
t
+
1
,那么
S(i)=T(i−st+1)
S
(
i
)
=
T
(
i
−
s
t
+
1
)
的LCP为
w
w
,又因为,得到
exi=w
e
x
i
=
w
。
2.
nexti−st+1≥ed−st+1
n
e
x
t
i
−
s
t
+
1
≥
e
d
−
s
t
+
1
;同理,
exi
e
x
i
至少为
ed−i+1
e
d
−
i
+
1
,但还可能更多,暴力拓展
ed
e
d
即可。
其实
nexti
n
e
x
t
i
的求法也是类似的。
考虑每拓展一次
ed
e
d
至少
+1
+
1
,所以时间复杂度是
O(n)
O
(
n
)
的。
实现中有个细节就是
ed
e
d
要和
i−1
i
−
1
取一个
max
max
。
代码:
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;
}
}