【接前篇】进阶的KMP

开篇

接上篇,我提出了一个问题:如果当我们的模式串是“ aaaab”这样的,我们应该怎么做?有的小伙伴就会说:“确定next,再写出KMP”,确实可以这样做,那好我们用这种思想去想一下:

在i=4时,可以发现s与p开始不匹配,我们先确定next[j]的取值,再j=next[j],从而确定j应该回溯到什么位置。
当j=4时,不匹配,j=next[j]=3;
当j=3时,不匹配,j=next[j]=2;
当j=2时,不匹配,j=next[j]=1;
直到当j=1时还是不匹配,于是让i+1,开始下一轮匹配。
在这里插入图片描述

显然,这样做是没有问题的,但是,细心的你已经发现了,在模式串位置4前面的字符都与位置4一样,既然4位置上都不想等,那么前面的也一定不会相等,这时,你会想,有没有一种办法让这样的情况直接略过,我想告诉你的是:当然有!
这就是我们今天要讲的内容:

KMP的进阶——nextval

刚刚我们已经试了用基础版next去做这个题,那我们就去比对的模式串字符前面有没有相同的字符,有的话就不需要进行比对,此时我们要做的就是修正next,修正后的next我们叫做nextval,也是一个数组。
求nextval

首先看下面的例子,模式串为“abaabcac”。
在这里插入图片描述
简单描述为:

  1. 第一位的nextval值必定为0,第二位如果于第一位相同则为0,如果不同则为1。> 2. 第三位的next值为1,那么将第三位和第一位进行比较,均为a,相同,则第三位的nextval值为第一位的next值,为0。
  2. 第四位的next值为2,那么将第四位和第二位进行比较,不同,则第四位的nextval值为其next值,为2。
  3. 第五位的next值为2,那么将第五位和第二位进行比较,相同,第二位的next值为1,则继续将第二位与第一位进行比较,不同,则第五位的nextval值为第二位的next值,为1。
  4. 第六位的next值为3,那么将第六位和第三位进行比较,不同,则第六位的nextval值为其next值,为3。
  5. 第七位的next值为1,那么将第七位和第一位进行比较,相同,则第七位的nextval值为0。7.第八位的next值为2,那么将第八位和第二位进行比较,不同,则第八位的nextval值为其next值,为2。

可能很多小伙伴看了上面的的解释还是不懂,别着急,下面是我的详细描述,相信你看了一定又会有新的感受。

我们很容易知道在第一个位置上是总是0,这时的next=nextval;
第二个位置,我们看a与b字符是否相等,很显然,不等,所以就有比较的意义,那么我们让i不动,j从1号位置开始比,此时的位置nextval=1,这个1就是来自nxet的1;
在这里插入图片描述
第三个位置,我们看到next=1,所以我们就把第三个位置上的a与第一个位置上面的字符a比较,此时的next是几就与第几个位置上面的字符进行比较,如果两个字符一样,我们就让nextval=0,如果不一样我们再去比较其他的,这里是一样的,所以nextval=0;
在这里插入图片描述
第四个位置,字符a与第二个位置上的字符b比较,如果相同,则让nextval=0,不同则让nextval=next,所以这里nextval=2;
在这里插入图片描述
第五个位置,字符b与第二个位置上的b相同,而第二个位置上的next=1,所以此时我们不能让nextval=0,而是继续让第二个位置上的b与第一个位置上的a进行比较,发现不同,我们就让nextval等于开始不相同的那个位置(二位置)上的next值,也即是nestval=1;
在这里插入图片描述
第六个位置,字符c与第三号位置上的字符a不同,则nextval=next=3;
在这里插入图片描述
第七个位置,字符a与都一个位置上的字符a相同,而第一个位置上的next=0,所以此时的naxtval=0;在这里插入图片描述
第八个位置,字符与第三个位置上的字符a不同,则nextval=next=2。

是不是感觉自己懂得差不多了呢?
但是还是感觉有点不清晰,所以我也把这一大段归结了一下,其实只有三个特点,小伙伴们可以试着自己去归纳一下:
这里为了简单描述,我们把上面的例子从左到右的比较者顺序称为前者与后者

后者与前者相同且前者的next=0,则nextval=0;
后者与前者相同但前者的next!=0,通过前者的next找到前者的前者的字符,比较前者与前者的前者字符是否相同,不同且前者的前者的next=0,则nextval=前者的naxt(如第五个位置);
后者与前者不同,则nextval=后者的next;

nextval的代码

为了让代码与我前一篇博客相呼应,这边也是用的对应的符号。

void get_nextval()
{
	int a=1,b=0;
	int nextval[20];
	nextval[1]=0;
	while(a<length(t))
	{
		if(b==0||t[a]==t[b])
		{
			++a;
			++b;
			if(t[a]!=t[b]) 
			    nextval[a]=b;
			else
			    nextval[a]=nextval[b];
		}
		else 
		    b=nextval[b];
	}
 }
希望这篇博客对你有所帮助!
GOGOGO

请添加图片描述

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值