作为408考生,数据结构绕不开KMP算法,网上各种求next数组的方法和结果竟各有不同,本文将带你探讨产生这种局面的原因和求next数组的两种方法。
我没去找,反正算的确实是对的。
要求i位置next值时,观察前一个位置,即i-1位置。
(1). 设置一个固定指针指向i-1位置,一个移动指针j首先指向i-1。
(2). 如果i-1位置的字符和j位置next指向的字符相同,则设置next为j位置next值+1。
(3). 如果不相同则让j指针移动。移动到目前next指向的位置。直到i-1位置的字符和j位置next指向的字符相同或者j位置next指向0,则设置next为j位置next值+1。
如:这里求序号3的next值,则观察序号2的next值,发现其next值指向序号1。
而序号1对应的字符a与序号2对应的字符不相同,故j继续移动,但此时发现
序号1的next为0,已经不能再往前了。故next取此时j指向的next+1。即0+1=1
上面的案例可能不好理解,不过我们可以得出以下几个结论帮助理解(假设要求第i位置的字符):
那么第一个字符和第二个字符next值的0和1又从而来呢?
第二字符的next很容易就可以知道:求其next值时只需要考虑第一个字符,因第一个字符前面所以不到其他字符了,所以第二个字符的next值就是第一个字符的next值+1。
那么第一个字符呢?第一个字符前面已经没有字符了,所以我们无法通过这种方法得到第一个字符的next值,而要追根溯源通过原理解释,所以想知道这个问题请看第二种方法。
在其他人的文章中你或许会看到同一模串会有不同的next数组。比如:对于ababaaababaa对应的next数组可能会有-1,0,0,1,2,3,1,1,2,3,4,5和0,1,1,2,3,4,2,2,3,4,5,6两种形式,但是仔细观察就会发现两个数组每个元素都相差1,那么到底哪个才是正确答案呢?
答案是:两个都有可能!会造成的这样差别的原因是数组教学中的经典问题——数组下标到底是从0还是1开始!第一个是数组从0开始的程序结果,第二个是数组从1开始的手算结果。
如果你已经充分理解了这种方法,请尝试自己编程实现一下吧!
这个方法简而言之就是:在通过前一个字符next串成的链中寻找第一个和前一个字符相同的结点。
当模串指针移动到j位置时匹配失败了,说明至少主串的指针i前面长度为j-1的子串和模串是相同的。那我们是否可以利用前面这段匹配相同的信息呢?显然是可以的,分析相同前后缀子串就是其中一种方法:如图,当我们发现j指针处不匹配了,需要将j指针向前移动。明显,主串的i-1、i-2、i-3与模串的123位置的字符是一样的。
那么我们可以直接将j回溯到4位置进行对比。
但是主串的匹配项不尽相同,而模串的总是一样的,所以我们只用转而求相对主串短很多的模串的相同前后缀就行了。
这个方法源自于KMP的原理,易于理解但是求解过程复杂费时,所以不建议考试用这种方法。如果了解KMP和next原理的同学可以直接跳过这个部分。
前缀字符串即除本身外可以构成前缀的串。
后缀字符串即除本身外可以构成后缀的串。
例:对于串 abcde,前缀字符串集={abcd,abc,ab,a},后缀字符串集={bcde,cde,de,e}。
这是KMP算法早期利用的模串信息,即next数组的前身。
部分匹配值=前缀字符串和后缀字符串最长相同子串的长度。
例:对于串 ababa,前缀字符串集={abab,aba,ab,a},后缀字符串集={baba,aba,ba,a}。最长相同子串为aba。故部分匹配值为3。
next数组又称前缀数组。
数值意义:它代表匹配失败时,模串指针该回溯的位置。
原理意义:它分析该字符前面的字符构成的子串中的最长相同前后缀子串。
今天没时间了,下次再写。
我写了一个简单的h5页面挂在unicloud上,可以获取输入字符串的next和nextval数组,对自己想法有疑惑的兄弟可以测一测。
如果你认为测试结果有问题可以私信我,毕竟赶急写的,难免会有些问题。
next数组测试网站