扩展KMP

参考和图片来自 这篇博客

exkmp是求解 最长共同前缀长度 的算法

重新定义 next 数组:

next[i] : 满足 t[i…m-1]=t[0…m-1] 的最长公共前缀

即:以下标 0 为首和以下标 i 为首的串的最长公共前缀长度

引入一个新的数组:

extend[i] : s[i…n-1] 与 t[0…m-1] 的最长公共前缀

即:以下标 i 为首的s串 和 以下标 0 为首t串 的最长相同前缀

在完成extend[0…k]的匹配后,定义匹配过程中所达到的最远位置为P:

p = i+extend[i]-1 最大时 的位置(0<=i<=k)

并且设取这个最大值的起始位置为po

在这里插入图片描述
即可表示为:S [ po , P ] = T [ 0 , P - po ]

计算 extend [ k + 1 ] :
由上式可以推出:S [ k + 1 , P ] = T [ k +1 - po , P - po ]
令 l = next [ k + 1 - po ]

考虑 2 种情况:

  • ① k + l < p

在这里插入图片描述
所以:S [ k + 1 , k + l ] = T [ 0 , l - 1 ]
如果 S [ k + l + 1] == T [ l ]
则有 S [ k + 1 , k + l + 1 ] = T [ 0 , l ] = T [ k + 1 - po , k + l + 1 - po ]
(由上面加粗的式子得出)
那么 next [ k + 1 - po ] = l + 1 (≠ l) 与 l 的定义矛盾,所以不存在

因此:extend [ k + 1] = l

注意:代码里是从 i - 1 的状态推到 i 的状态,所以 l = nx[ i - po ]

  • ② k + l >= p

在这里插入图片描述
S [ P + 1 ] 之后都没有匹配过
所以从 S [ P + 1 ] 和 T [ P + 1 - k ]匹配,直到发生失配为止
此时 extend [ i ] 等于新匹配的长度+ (p+1-k),更新po的位置

计算next数组的过程和计算extend[i]的过程完全一样 将它看成是以T为母串,T为字串的特殊的拓展kmp算法匹配就可以了

int nx[maxn];
int ex[maxn]; 
void getnx(string x){
	int m=x.size();
	nx[0]=m;
	int j=0,po=1;
	while (j+1<m && x[j]==x[j+1]) j++;
	nx[1]=j;
	for (int i=2; i<m; i++){
		int p=nx[po]+po-1;
		int l=nx[i-po];
		if (i+l<p+1) nx[i]=l;
		else {
			j=max(0,p-i+1);
			while (i+j<m && x[i+j]==x[j]) j++;
			nx[i]=j;
			po=i;
		}
	}
}

void exkmp(string s, string t){
	int n=s.size(),m=t.size();
	getnx(t);
	int j=0,po=0;
	while (j<n && j<m && s[j]==t[j]) j++;
	ex[0]=j;
	for (int i=1; i<n; i++){
		int p=ex[po]+po-1;
		int l=nx[i-po];
		if (i+l<p+1) ex[i]=l;
		else {
			j=max(0,p-i+1);
			while (i+j<n && j<m && s[i+j]==t[j]) j++;
			ex[i]=j;
			po=i; 
		}
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值