next数组定义:
next[i]:模式串子串s[0…i]的最长公共前后缀中的前缀右边界下标.
next数组的作用:
next[i]:在模式串的i字符与主串失配时,模式串滑动调整的下一个位置,从这个位置继续后边的匹配.
原理:
当模式串字符i与主串失配时,前面已匹配的字符可以加以利用.模式串已匹配成功的后缀,如果与模式串前缀相等,则模式串移动到这个与后缀重叠的位置.由于前缀与后缀相等,于是这么移动之后,可以从前缀的下一个位置继续匹配.这个就是公共前后缀.显然,我们要求出模式串每个位置的最长的公共前后缀长度,就是next数组,它只跟模式串本身有关.
生成next数组时,k=next[k],理解:
while(k!=-1 && s[k+1] != s[i])
k = next[k];
扫描模式串,生成next数组,就是求模式串各个位置的最长公共前后缀长度.
已知next[i-1] = k,求next[i]
根据next数组定义,s[0,…,k]与s[i-1-k, i-1]相等.
如果s[i]与s[k+1]失配,公共前后缀无法继续延伸,要回溯一步.
具体讲,前缀串s[0,…,k]的右边界往左收缩,后缀串s[i-1-k,…, i-1]的左边界往右收缩.收缩后的位置k’<k,使得s[0,…,k’]与s[i-1-k’,…,i-1]相等. 然后尝试比较s[k’+1]与s[i],如果相等,这就是退而求次的s[0,…i]的最长公共前后缀,即next[i]的值.
那么k’是多少呢?
因为s[0,…,k]与s[i-1-k,…, i-1]相等
所以s[k-k’,…,k]与s[i-1-k’,…,i-1]相等
于是问题变成了,在s[0,…,k]中,求k’,使得s[0,…,k’]与s[k-k’,…,k]相等
这就是求s[0,…,k]的最长公共前后缀嘛,即next[k]
等式0: 求k’<k,使得s[0,…,k’]与s[i-1-k’,…,i-1]相等
等式1: 已知next[i-1] = k,根据next的定义, s[0,…,k] = s[i-1-k,…, i-1]
等式2: 根据等式1, s[k-k’,…,k] = s[i-1-k’,…,i-1]
根据等式2, 将等式0转化为:求k’<k,使得s[0,…,k’]与s[k-k’,…,k]相等
等价于:求s[0,…,k]的最长公共前后缀,即next[k]
于是:k’ = next[k]
根据next的定义,k’ = next[k]
然后在k’的基础上,尝试比较s[k’+1]与s[i].
求k’的过程一直迭代,直到k’=-1.表示退无可退,没有可利用的公共前后缀.只能从头开始,比较s[0]与s[i].