next数组求解中,相信对于求解过程依赖于前一位的值。如果p[j] == s[i], 那么++j这些都容易理解,就是如果next数组中求值的这个这位的字符,如果和前缀的下一位字符继续相同的话,说明前缀字符串可以继续加长。这就是next数组的值=++j的意思。
但是如果不同呢,这时就需要减少前缀的长度进行比较,于是算法中给出了j=next[j],就是说前缀长度取值变成了next[j]继续比较。
这里的确很让人疑惑,为什么要取值next[j]呢?
在说这个问题之前,先要说一个前提,就是为什么模式串下一位不同,前缀就要减少,不能增加吗?答案是不能,如果可以增加的话,那么上一位next数组的就还可以增大,也就是j值就是不正确的。因为上一位已经求出了最大的j值。所以不存在更大的j值可以匹配的情况。所以下一位不同,那么j值只能减小,才能找到可能匹配的前缀。
明确了上面这个前缀长度只能减少的结论。那问题就好办一些了。由于j要减少,对于后缀来说,也就是i指向的位置(包括i)往前的长度,要减少。我们先考虑认为长度减少一个。就来研究这个长度,也就是j-1长度的字符串。
我们需要同时研究前缀j-1的字符串,和i前面(含i)j-1的长度的字符串。这两个字符串现在有什么关系呢?我们发现,前缀除掉第一个字符剩下的字符串,刚好是不含i的后缀字符。
如果不理解,大家可以想象一下,两个本来一样的木头,第一根(前缀)后面砍掉一块,第二根前面砍掉一块。那么他俩的关系,就是第一根前面再砍掉一块,和第二根后面砍掉一块,他们仍然是一样的。
明白了前缀除掉第一个字符剩下的字符串,刚好是不含i的后缀字符。这个道理,我们往下继续。我们思考如果我们只想比较i字符串的话,就要设法找到不含i的j-1字符串, 也就是i前面j-1-1的字符串中能够匹配到前缀一样的这个字符串最大的那个长度。而这个j-1-1的字符串刚好就在前缀中的后面。所以对于j-1的前缀。我们只需要找到它的最大前后缀,就找到了能够匹配i前面的能匹配的最大长度的前缀。
而对于j-1的前缀寻找他的最大前后缀,就是next[j]的值,前面已经求过了。只需要取。
这就是为什么接下来j=next[j]的原理。
重置了这个指针之后,然后还是重复第一步的动作,比较当前值和最大前缀的后一位的值是否相同。循环往复,一直查到j=1的这个最短长度,就直接赋值为1,后比较下一个了。