在kmp算法中,最难理解的那部分就是next数组的求解原理,今天看懂了一点点,现在记录一下
我们假设有这么一个字符串(模式串):abac......abab.......
为方便起见,我们用数组 S 称呼这个字符串
下标 | 0 | 1 | 2 | 3 | ................ | 5 | 6 | 7 | 8 | 9 | .............. |
值 | a | b | a | c | ................ | a | b | a | b | .............. | |
k1 | k | j | j+1 |
如上图所示,我们可以知道:当 j=8 的时候,next[j]=3(因为S[0]S[1]S[2] = S[5]S[6]S[7]),现在我们来求next[j+1]
- 如果S[k] = S[j],即S[3] = S[8], 那么 next[9] = next[j+1] = next[j] + 1 = k + 1 = 4
- 如果S[k] != S[j],即如上图所示的S[3] != S[8],那该怎么办呢? 下面着重讨论这个问题
由表格中的数据我们可知,由于S[k] != S[j],所以next[j+1]不可能为k+1这么简单,也就是说 next[j+1] 的长度不可能比 next[j] 再长了,所以我们只能寻找更短的相同前后缀
现在我们让 k1 = next[k](本来在代码中应该是:k = next[k],从而构成一个循环,但这里为了方便描述故而采用 k1 的说法,千万不要被误导),由于 k = 3,所以新的 k1 = next[3] = 1(前提是 next[k] 真的有相同的前后缀)(因为S[0] = S[2]),下面重点来了:
因为 S[0]S[1]S[2] = S[5]S[6]S[7] , 所以S[2] = S[7], 又因为有 S[0] = S[2],所以 S[0] = S[7],此时如果有S[k1] = S[j],那么就有:S[0]S[k1] = S[7]S[j],那么就可推断出 next[j+1] = next[k] + 1
最后我们发现 S[k1] = S[1] = b,S[j] = S[8] = b, 所以S[k1] = S[j] , 所以next[j+1] = next[k] + 1 ==> next[9] = 2
(2)上面的情况是 S[k1] = S[j],所以才有 next[j+1] = next[k] + 1, 那要是 S[k1] != S[j] 呢?又会是个什么情况
下标 | 0 | 1 | 2 | 3 | ................ | 5 | 6 | 7 | 8 | 9 | .............. |
值 | a | b | a | c | ................ | a | b | a | d | .............. | |
k2 | k1 | k | j | j+1 |
如上面表格所示:此时 k1 = 1, j = 8, S[k1] != S[j] 即:b != d, 这个时候我们继续让 k2 = next[k1] = next[1] = 0, 由于S[k2] != S[j], 即:S[0] != S[8], 所以继续让 k3 = next[k2] = next[0] = -1
这个时候 k3 = -1,说明 next[j+1] 没有相同的前后缀,所以我们就让 next[j+1] = 0,并且重新开始计算 next[j+2] 的相同前后缀,对应的代码就是:j++; k++; next[j] = k; (因为 k 自增之后才为0,j 自增刚好用于计算下一个字符的相同前后缀)
说明:我这里只是描述了其中一种情况而已,但是已经足够用来说明next数组的求解原理了,表格中的红色字体部分可以替换成更长的字符序列,都没有任何问题,因为原理都是一样的
下面是KMP算法的完整代码: