简介
KMP大家都耳熟能详,扩展KMP只是一个扩展版而已,字面意思啦!
我记得以前打过这个复习小记的,但是不知为何失踪了。
KMP与扩展KMP的对比
KMP的next[i]表示从1到i的字符串s,前缀和后缀的最长重叠长度。
EXKMP的next[i]表示从1到i的字符串s,和从i到n的字符串st的最长重叠长度。
也就是说KMP是向前的匹配,EXKMP是向后匹配。
扩展KMP问题是KMP问题的补充和加难。
具体内容
重要数组
给定母串S,和子串T。定义n=|S|, m=|T|。
extend[i]=S[i..n]与T的最长公共前缀长度。
next[i]=T[i..m]与T的最长公共前缀长度。
需要线性解决的问题
线性求出extend和next数组。
解决方法
设extend[1..i-1]已经算好,并且在以前的匹配过程中到达的最远位置是p,对应的点是k。(就是说S[k…p]=T[1…extend[k]],k是1到i-1的匹配中匹配到的最远点对应的位置)。
像KMP一样,假设已经求得了next数组。
根据定义S[k…p]=T[1…extend[k]],因为k…p覆盖i,所以S[i…p]=T[i-k+1…extend[k]],因为要与T的前缀匹配,所以还要把T[i-k+1…extend[k]]与前缀匹配才行,因为next[i-k+1]是T从i-k+1位置开始的字符串与T的前缀最长匹配的长度,所以T[1…next[i-k+1]]=T[i-k+1…i-k+next[i-k+1]],因为S[i…p]=T[i-k+1…extend[k]],p覆盖i,所以extend[i]至少为next[i-k+1],设l=next[i-k+1]。
p=k+extend[k]-1;l=next[i-k+1];
因为现在extend至少为l了,因为利用
现在就要分两种情况了:
fo(i,1,n){
p=k+extend[k]-1;l=next[i-k+1];
if(l+i>p){
j=p-i+1;if(j<0)j=0;
while(i+j<=n&&s[j+1]==st[i+j])j++;
k=i;
extend[i]=j;
}
else{
extend[i]=l;
}
}
1、i+l< p:
因为p是目前已经匹配过的地方,l就变成了extend[i]的最大值,否则就违反了next[i]的T从i以后的字符串与T的最长公共前缀。
else{
extend[i]=l;
}
2、i+l≥p:
因为大于p是还没有匹配过的地方,所以进一步匹配可能可以让答案更大。然后只用往后匹配并更新最远匹配点p的值和对应点k的值。
j=p-i+1;if(j<0)j=0;
while(i+j<=n&&s[j+1]==st[i+j])j++;
k=i;
extend[i]=j;
时间证明
感性证明一下,每个点都只会被访问一次。自然时间复杂度是O(n)。
推荐题目
【GDOI2014】beyond
。。。用的不是很多,就做过这一道题,网上应该很多,O(∩_∩)O~
由于本人是个蒟蒻
目前多扩展KMP知道的也只有这么多了。