模式串中所有“以第i位结尾的子串(后缀子串)”显然共i个,不过我们要排除掉最长的一个即P[1~ i],剩下一共i-1个即:
子串 | 长度 |
P[i] | 1 |
P[i-1~ i] | 2 |
P[i-1~ i] | 3 |
... | |
P[3 ~ i] | i-2 |
P[3 ~ i] | i-1 |
模式串中所有“长度不超过i的前缀(前缀子串)”显然共i个,不过我们要排除掉最长的一个即P[1~ i],剩下一共i-1个即:
子串 | 长度 |
P[1] | 1 |
P[1 ~ 2] | 2 |
P[1 ~ 3] | 3 |
... | |
P[1 ~ i-2] | i-2 |
P[1 ~ i-1] | i-1 |
上面我们分别得到了关于下标i的一组“后缀”和一组“前缀”
然后我们用每一个“后缀子串”和对应相同长度的“前缀子串”进行匹配,即考虑下面所有的“子串对”:
后缀子串A | 前缀子串B | 长度 |
P[i] | P[1] | 1 |
P[i-1 ~ i] | P[1 ~ 2] | 2 |
P[i-2 ~ i] | P[1 ~ 3] | 3 |
... | ||
P[3 ~ i] | P[1 ~ i-2] | i-2 |
P[2 ~ i] | P[1 ~ i-1] | i-1 |
运气好的话总有一对或多对“后缀”和“前缀”完全相等
那么NEXT[i]就代表最长的一对“后缀=前缀”的长度
如果很不幸没有一对相等的后缀和前缀,那么NEXT[i] = 0
*例:
i = | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
P[i] = | a | b | a | b | a | b | c |
NEXT[i] = | 0 | 0 | 1 | 2 | 3 | 4 | 0 |
换一种说法,比如上例中NEXT[5]的值是3,代表:
如果模式串前5位都与目标匹配,但下一位(6号位)发生了失配,那么就右移整个模式串!
移动多少呢?也就是把3移动到5的位置!
想象模式串abababc是一张小纸条,那么用你的大手按住3号位的a,向右拖到5号位,连同整张小纸条一起!
为什么可以这样移?因为模式串的123位和345位一样(都是aba,长度是3)
再换一种说法,比如上例中NEXT[5]的值是3,代表:
如果模式串前5位都与目标匹配,但下一位(6号位)发生了失配,就像
T:ababaccccccccabababca
P:abababc
此时如果是Brute-Force的话,则需要右移模式串1位,然后T和P的指针都返回起点,重头开始比较……
但如果是KMP的话,T的指针不需要变,还是指向第6位(即失配的那一位)
而只要把模式串p右移一下,让绿色的两个aba对齐,继续比对T的第6位
---
这样一来,在整个KMP的过程中,目标串T的指针从没有发生回溯,始终向右走。
由于T的指针绝不会回头,并且任何一对T[i]与P[j]最多只比较一次(就算是Brute-Force也是最多只比一次)
所以算法的复杂度奇妙的被锁定到了O(N+M)
copyright by
scarlet.MP5