对于KMP算法的一些自我理解


说明


KMP算法要说难不难,说简单也不简单,不懂的时候完全不懂。看了好多博客说理解后又发现是如此简单,在KMP算法中最重要的也就是关于next数组的求解了,这也是最主要的难点,所以便打算把我自己的理解写出来用于加深自己的印象


首先对于一个算法,首先我们要明确KMP做什么?还有怎么实现的问题?


KMP算法是由D.E.Knuth,J.H.Morris和V.R.Pratt提出的,用于字符串模式匹配的算法。例如在一个字符串里找另一个字符串出现的位置。

我们设有两个字符串变量p和t,我们要在p中找到t在p出现的所有位置。

首先我们要明确next数组的意义,next[p]=k表示为在t[0]……t[p-1]的最大相同前缀和后缀的长度为k。j为当前匹配到了字符串t的哪一个位置,k为当前最大相同前缀和后缀的长度。我们初始化next[0]=-1,这样当t[0]就匹配失败的时候,能够确保我们的串能够向后面移动。
以下是求解next数组的函数

void get_next(string t,int next[])
{
	next[0]=-1;
	int j=0,k=-1;
	while(j<t.length()-1){
		if(k==-1 || t[j]==t[k]){
			j++,k++;
			next[j]=k;
		}else{
			k=next[k];
		}
	}
}

为了解释上面的代码,我们假设当前有字符串t[0]…t[j-k]…t[j],并且设最大相同前缀和后缀长度为k,我们假设现在对t[j-k]……t[j-1]和t[0]……t[k-1]两个字符串已经比较了,为了确认对于字符串t[0]……t[j]的k值,我们就得比较t[j]与t[k]

现在,我们来理解下面两种情况:

1.当t[j]==t[k]的情况

我们知道,此时我们有next[j]=k(因为你前面部分的都处理了当然知道数值啊),表示t[0]……t[j-1]部分的最大相同前缀和后缀的值为k,当t[j]==t[k]成立时,我们就有next[j+1]=k+1;这个情况很简单,大部分都能理解这一部分。


2.当t[j]!=t[k]的情况

因为t[j]!=t[k],那么在t[0]……t[j]中,最大相同前缀和后缀的长度不会超过k值。我们假设这个长度为p,则我们需要比较t[j-k]……t[j]和t[0]……t[p]两段字符串,因为我们t[j-k]……t[j-1]和t[0]……t[p-1]比较过了,我们只需要比较t[j]和t[p]是否相等就行了,当两个相等时,则最大长度为p,即next[j]=p,若不相等,则p的大小还要减少,又在求解next[j]的时候,我们next[0]……next[j-1]已经求解了,即t[0]……t[p-1]部分的最大相同前缀和后缀的长度已经确定(因为p<j),我们这时候可以这样想,在t[0]……t[p-1]对应的next[p-1]的值确定了,那么当t[p]!=t[j]的时候,next[j]的值不会大于next[p-1]+1,所以我们可以直接更新p=next[p],然后再用k替换p(即从长度为k开始枚举)就有了k=next[k]这串代码。

next数组的求解理解后剩下的就很简单了
以下是代码

int KMP(string s,string t)
{
	int* next = new int[t.length()];
	get_next(t,next);//	求解next数组
	int k=-1;//k记录当前t匹配到的位置
	for(int i=0;i<s.length();i++){
		while(k>-1 && s[i]!=t[k]){//当s与t不匹配的时候回溯
			k=next[k];//回溯,具体看上面对k=next[k]的解释
		}
		if(t[k+1]==s[i]){
			k++;
		}
		if(k==t.length()-1){//在s中找到了t时
			return i-t.length()+1;
		}
	}
	return -1;
}

最后,这是我第一次尝试着写博客,感觉脑子也有点乱,如果有意见或者错误欢迎评论区指出QAQ

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值