扩展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函数即可

例题2:

CF126B

思路:


代码

posted @ 2024-05-03 13:59  MENDAXZ  阅读(5)  评论(0编辑  收藏  举报