学KMP算法的时候,对next数组的求解过程感到费解,遂在此记录一种从递归的角度理解next数组的求解过程。
func getNextArray(pattern string) (next []int) {
n := len(pattern)
next = make([]int, n)
if len(pattern) == 0 {
return next
}
next[0] = -1 //若next[0] = 0,匹配的时候会出现死循环
if len(pattern) == 1 {
return next
}
next[1] = 0 //即使next[1] = next[0],也必须令next[1] = 0
k, i := 0, 1
for i < n-1 {
//[1]
if pattern[i] == pattern[k] {
i++
k++
next[i] = k
} else {
//[2]
for k >= 0 && pattern[i] != pattern[k] {
k = next[k]
}
if k == -1 {
k = 0
i++
next[i] = 0
}
}
}
return next
}
[1] 此处可以理解为,以 pattern.substr(0, k + 1) 为新的模板字符串,以 pattern.substr(k + 1, j - k) 为新的待匹配字符串进行匹配。
[2] 匹配的过程中,发现新模板字符串和新的待匹配字符串存在不一致的字符,所以需要根据next数组回退新模板字符串的指针,即 k = next[k]。因为一直有 k <= i,所以此时 next[k] 一定是已经求过的,这也算一种动态规划吧。
以上代码参考,原代码比较简练:
public static int[] getNext(String ps) {
char[] p = ps.toCharArray();
int[] next = new int[p.length];
next[0] = -1;
int j = 0;
int k = -1;
while (j < p.length - 1) {
if (k == -1 || p[j] == p[k]) {
next[++j] = ++k;
} else {
k = next[k];
}
}
return next;
}