1. next数组 到底是什么意思?
next数组作为KMP算法里的核心部分,数组里每一项的值决定了在主串(即原字符串、被搜索的字符串)匹配失败后,子串(即目标字符串)需要重定位的位置。让我们用一个最最简单的例子来诠释如何生成一个next数组。
首先,next数组的取值只和子串有关。
比如有一个子串,值为:“A B C A B C D”。我们直接来生成next数组里,第二个C(后续记为C2)对应索引的值,即next[5]=?。
很简单,只需找出“从子串首字符开始向右”,和“从C2 开始 向左”的两个相同且最长的串即可,next[k]的值即为这两个串其中之一的长度。在这个例子里,即位于字符串开头的“A B C”,和从C2开始,向左的“A2 B2 C2”。所以next[5]=3,为上述两串之一的长度。
综上,示例里字符串的next数组即为
| A | B | C | A | B | C | D |
|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 1(A和A2) | 2(AB和A2B2) | 3(ABC和A2B2C2) | 0 |
2. 为何匹配失败后,需移动子串的指针到next[k]的位置?
举个例子,比如我们正在将主串“...ABCABCY...” 匹配第一点里叙述的子串“ABCABCX”。
当Y匹配到X时,此时匹配失败。但是很容易看出来,X前面的所有字符,和Y前面6位字符肯定是完全相同的,不然也不会走到Y匹配X这一步来。
∵ 由next数组可知X前的C2对应的next[5]=3
∴ X前三个字符A2B2C2和子串开头3个字符ABC一定是相等的
∵ X前面的所有字符,和Y前面6位字符完全相同
∴ Y前三个字符A2B2C2和它们前面3个字符ABC一定是相等的
∴ 下面图片内的四组ABC一定是完全相等的,黄色组的ABC也等于红色组的ABC
∴ 与其把子串的指针直接回退到0重新开始匹配,不如直接把黄色组和红色组对齐,直接拿Y开始对比A2,节约了对比完全相同的两组ABC的时间,即 移动位数 = 已匹配的字符数 - next[k] = 6 - 3 = 3
3. 为何匹配失败后,无需移动主串的指针?
用第二点里的主串“...ABCABCY...”来举例子,对于Y,成功的匹配子串的位置相对于它,无非就以下三种情况。
1、成功匹配的子串在Y的前面(不包含Y)
2、成功匹配的子串包含了Y
3、成功匹配的子串在Y的后面
现在,因为在Y处匹配失败了,那么成功匹配的情况就绝对不可能是1和2,那我们还把主串的指针从Y移动到它之前干什么呢?都不用考虑这样到底会不会漏掉前面的某些子串了,即使全漏掉,也不会对最后成功的匹配产生影响,因为既然已经走到Y来了,就说明前面的子串一定没有成功匹配,我们只需要继续向后查找即可。