KMP算法
参考视频:https://www.bilibili.com/video/BV1AY4y157yL/
KMP模式串指针回退:
next数组计算:
func KMP(str string, pattern string)int{
m := len(str)
n := len(pattern)
if m == 0 || n == 0{
return -1
}
// next[i]记录了以i结尾的pattern最长公共前后缀的长度
next := nextGen(pattern)
i, j := 0, 0
for i < m{ // i永不回退
if str[i] == pattern[j]{
i++
j++
}else{
if j == 0{ // pattern首字母就不匹配
i++
}else{ // j回退到pattern[0:j]最长公共前缀的位置
j = next[j-1]
}
}
if j == n{ // 匹配成功
return i-n
}
}
return -1
}
func nextGen(pattern string)[]int{
// 返回以i结尾字符串最长公共前后缀的长度
n := len(pattern)
next := make([]int, n)
if n == 0{
return next
}
next[0] = 0
prefixLen := 0
for i := 1; i < n; {
if pattern[prefixLen] == pattern[i]{ // 下一个字符依然相同
prefixLen++
next[i] = prefixLen
i++
}else{
if prefixLen == 0{
next[i] = 0
i++
}else{
// prefixLen此时为next[i-1]的值,表示前一个位置最长公共前后缀长度
// 相当于 prefixLen = next[next[i-1]-1],意味着已经有prefixLen个字母匹配
// 下一个待匹配位置为index = prefixLen,因此再判断 pattern[prefixLen] == pattern[i]
prefixLen = next[prefixLen-1]
}
}
}
return next
}