KMP算法——详解next数组

  • Post author:
  • Post category:其他


令人烦恼的next数组,本文是作者自己的理解与思考,并不完善,只是为了提示自己,如果您已研究了KMP算法,本文或许对您的帮助并不大

next数组完成的任务:

在这里插入图片描述

当s1与s2字符串比较到上图所示位置时,拥有next数组的KMP算法不需要像BF算法一样:

  • 将 j 回退到开始的第二个字符
  • 将 i 退回到字符串头部

而是:

  • 将 i 回退到第二个字符b处
  • j 不动

next数组的创建:

先来看看代码:

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

不理解?那太好了,本文就是为此而写的;

首先我们先来看一个例子,先认识一下next数组的内容:

在这里插入图片描述

💡你必须知道下面的

概念

;


前缀字符串

:从0下标开始,到j-1下表对应的字符位置结束(注意:不是到i-1位置,只要和i-1位置的字符一样就可以了);


后缀字符串

:从与0下标字符一样的位置开始,到i-1位置结束;


公共字符串

:前缀字符串和后缀字符串相等时的字符串;


next值的含义



(1):代表最长公共字符串的长度。

(2):以next值为下标的字符是前缀字符串即将插入的下一个字符;


j值代表的含义



代表后缀字符串即将插入的下一个字符;

❗❗❗重点来了,如何让机器算出某个位置的next值!

以算6下标的next值为例,博主的理解:

在这里插入图片描述

在这里插入图片描述

(1):6位置的next值代表的是0-5下标的最长公共子串,那么将目光投向5下标

(2):5下标的next值是2,表明0-4下标的最长公共子串:“ab”,也就是说前缀和后缀字符串都是”ab”;还表明前缀字符串即将插入下标为2的字符

(3):j指向的是后缀字符串即将插入的字符: ‘a’

(4):前缀字符串插入下一个是”aba”,后缀字符串插入也是”aba”,因为”ab”本来就是最长子串,那插入相同的字符最长子串不就是”aba”嘛

(5):next值就是最长公共子串的长度,所以6位置的next值为3。

总计:

找到前一个值的最长字串,看插入前缀的字符和插入后缀的字符是否相等,相当于在前一个值得基础上各加了一个相同得字符,所以直接在前一个next值上++就行了。

上面的next值计算其实对应者代码的第一个if语句,那看起来毫无逻辑的第二个又如何理解呢?

我们算7位置的next值:

在这里插入图片描述

还是按照上面的方法,只不过这次我们发现前缀插入的值和后缀插入的不一样了,那我们就不能直接在前面的基础上++,那该怎么办呢?代码告诉我们 “k=next[k]”,那么如何理解?

在这里插入图片描述

以上面的例子为例,k=next[3],也就是说k之后变为1了,那意味这什么,0-2下标的最长公共子串为1,对应的前缀和后缀字符串为’a’,原来的前缀和后缀字符串是相等的,那么不就意味着你在新的前缀后面插字符和你在原来的后缀里面的前缀插字符一样,又因为新前缀和新后缀相等,不就意味着在原来前缀后面插字符和在原来后缀后面插字符是一样的嘛,所以在新前缀里面插字符和在旧后缀后面插字符是一样的,所以我们只需不断判断然后k=next[k]直到k与j所指字符一样为止。

总结:主要是注意前后缀是完全相等的,所以前缀只要还有公共最长字串,那么后缀与前缀完全相同,没有的话就是说前缀的第一个字符和前缀的最后一个字符不相等,对应搞后缀就是后缀的第一个字符和后缀的最后一个字符不相等,而前后缀完全相同,也就说前缀的第一个和后缀的最后一个不相同,也就意味着新插入的字符单独作为最长公共子串存在!

博主自己是思考清楚了,但是好像表达得不是很好,如有不懂,还请私信博主,将最快时间解答。



版权声明:本文为qq_55229149原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。