exkmp学习小结

exkmp主要用于求以下的问题:

给定文本串S,模板串T n=|S|,m=|T| 数组ext[i]表示S[i..n]与T的LCP的长度(LCP表示最长公共前缀) 要求在线性的时间内求出ext[1..n] 。(c自某位大佬的ppt)

正文:

首先,我们定义一个next[1...m]数组表示模板串T从第i位开始与自身的最长公共前缀。假设next[i]=ai,那么T[1~ai-1]与T[i~i+ai-1]是匹配的。

如何去求next数组呢?

假设我们已知next[1~i-1],现在求next[i]。我们在next[1~i-1]中记录一个p表示之前最长延伸到的位置,并把p的坐标记录id。也就是说next[id]=p(1<=id<=i-1)且p为next[1~i-1]的最大值。那么如果p>i,T[i~p]和T[i-id+1~p-id+1]匹配。那么next[i]>=next[i-id+1]。

现在分两种情况讨论,我们设j=next[i-id+1].

第一种i+j<=p,则next[i]=next[i-id+1]。

因为next[i-id+1]最多匹配到i-id+1+j-1也就是说T[i-id+1+j]与T[j+1]不匹配。同样,因为T[id~p]与T[1~next[id]]匹配,所以T[i+j]与T[j]

不匹配。则next[i]=next[i-id+1]。

第二种i+j>p(也就是i+j-1>=p)

如果i+j-1>p毫无疑问我们不能确定next[i]=next[i-id+1],所以我们暴力判断后面是否匹配,并更新next[i]。

那如果i+j-1=p呢,非常蠢的我想了很久才发现这也是要判断是否匹配的。由于T[i-id+1+j]与T[j+1]不匹配,所以next[i-id+1]=j,但我们不能确定T[i+j]不与T[j+1]不匹配,因为i+j已经超过p了。

和kmp一样,我们可以用同样的方法求ext数组,方法都基本一样的。

code

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 10000
int next[N],ext[N],n,m,p,id;
char s[N],t[N];
int main()
{
	
	scanf(" %s",s+1);
	scanf(" %s",t+1);
	n=strlen(s+1);
	m=strlen(t+1);
	next[1]=m;
	for(int i=2;i<=m;i++)
	{
		int j=next[i-id+1];
		if(i+j>p)
			for(j=max(p-i,0);i+j<=m&&t[j+1]==t[i+j];j++);
		next[i]=j;
		if(i+j-1>p)
			id=i,p=i+j-1;
	}
	
	id=p=0;
	for(int i=1;i<=n;i++)
	{
		int j=next[i-id+1];
		if(i+j>p)
			for(j=max(p-i,0);i+j<=n&&t[j+1]==s[i+j];j++);
		ext[i]=j;
		if(i+j-1>p)
			id=i,p=i+j-1;
	}
	for(int i=1;i<=m;i++)
		printf("%d ",next[i]);
	printf("\n");
	for(int i=1;i<=n;i++)
		printf("%d ",ext[i]);

}

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值