扩展KMP
需要解决的问题:
如果要用哈希统计从s中每一位字符开始最多可以匹配多少位p中的字符,需要用到二分查找,此时时间复杂度为O(nlogm+m),其中n表示s的长度,m表示p的长度
更好的方法?
扩展KMP(Z函数),能够以线性的时间复杂度求出一个字符串s和它的任意后缀s[i]……s[n]的最长公共前缀的长度(从s[i]开始,能够从头开始匹配s的最大长度)
上面的问题等价于在P#S上面求Z函数
与KMP的差别:KMP是以s[i]作为结尾,Z函数式以s[i]作为开头
如何求Z函数?
z[1]=0,然后从2到n枚举i,依次计算z[i]的值
假设我们要计算第i个位置的值z[i],此时z[1]……z[i-1]都已经计算好了
对于j,有s[j]……s[j+z[j]-1]和s[1]……s[z[j]]完全相等
为了计算z[i],在枚举i的过程中,我们要维护R最大的区间[L,R],其中L=j(j<i),R=j+z[j]-1
初始时,L=1,R=0;
接下来来看看计算z[i]时可能发生的几种情况
代码部分(下标从1开始)
void exkmp(){
int L=1,R=0;
z[1]=0;
for(int i=2;i<=n;i++){
if(i>R) z[i]=0;
else {
int k=i-L+1;
z[i]=min(z[k],R-i+1);
}
while(i+z[i]<=n&&s[z[i]+1]==s[i+z[i]]) ++z[i];//暴力匹配部分
if(i+z[i]-1>R) L=i,R=i+z[i]-1;//右端点最大的 区间
}
}
例题1:给你两个字符串a,b,字符串均由小写字母组成,现在问你b在a中出现了几次?
思路:b#a,将b与a拼起来,然后求一遍Z函数即可