KMP
- 主要有两个函数,一个得到 next 数组的函数,另一个是 kmp 外层函数;
- next[] 数组:对于i+1位置的元素,求的是 0-i位置的 “最长前缀=最长后缀”这个问题的答案
- str1 是原串,str2 是子串
- kmp()返回有没有包含关系(或者第一个出现的位置)
getnext()
getNext()核心代码就如下所示
while (i < next.length) {
if (ms[i - 1] == ms[cn]) {
next[i++] = ++cn;
} else if (cn > 0) {
// 当前跳到cn位置的字符,和i-1位置的字符配不上
cn = next[cn];
} else {
next[i++] = 0;
}
}
getnext()的解释:最长前缀 = 最长后缀
这部分是求当 i(位于 str1 内部)
while 中分为三个分支:
- 第一个分支是 i-1 位置的值 和 cn 位置的值 相同;
初始 i 等于 2,因此初始的下标是 1,第二个位置的值;初始的 cn 等于 0,第一位置的值。
因为对于至少长度为 3 的字符 a a b 才有意义求它的 next 数组(只有 next[0]是-1;next[1]=0)。对于 aab 来说,“最长前缀 = 最长后缀”这个问题的值就等于 1 —— 意义就是,前面 i 个元素,和从后面倒起的 i 个元素,正序上来说是相等的。
而求 next 数组的核心意义就在于此;
-
第二个分支 是 cn 并没有越到 0 以下,就不断追溯这个过程。cn = next[cn]
-
第三个分支确定是 i 位置 的值的最后可能的一步。
以下给出一个重复跳转的例子,以解释说明这个while循环:
求 aba c aba X f aba c aba ? ?+1 这个字符串的next数组
其中X是某一个假设的字符,?也是一个字符,?+1表示 再往下一个字符。
X,?,?+1 这些是什么不重要,可以当成是一个变量。
假设当前已经求好 问号之前以及问号位置的next值了,要求 ?+1 位置的next值(next[] 数组:对于i+1位置的元素,求的是 0-i位置的 “最长前缀=最长后缀”这个问题的答案)。那么有以下几个步骤:
- 如果 X 值等于 ?处的值,那么 next[?+1] = 8 ———— 也就是 ++7
- 如果 X 不等于 ?, 那么根据X位置的next值往前找,next[X],显然,aba = aba,next[X] = 3;此时比较 3 位置的值 ‘c’ 是否等于?的值,如果等于,那么 next[?+1] = 4 ———— 也就是 ++3
- 如果 str[3] 还是不等于 ?,那么