找到text中模式pattern的出现的pos
时间复杂度o(m + n)
def kmp(self, text: str, pattern: str) -> List[int]:
m = len(pattern)
pi = [0] * m
c = 0
for i in range(1, m):
v = pattern[i]
while c and pattern[c] != v:
c = pi[c - 1]
if pattern[c] == v:
c += 1
pi[i] = c
res = []
c = 0
for i, v in enumerate(text):
v = text[i]
while c and pattern[c] != v:
c = pi[c - 1]
if pattern[c] == v:
c += 1
if c == len(pattern):
res.append(i - m + 1)
c = pi[c - 1]
return res
func kmp(text, pattern string) (pos []int) {
m := len(pattern)
pi := make([]int, m) // 前后缀匹配的长度, 不包括自身
cnt := 0
// dp
for i := 1; i < m; i++ {
v := pattern[i]
// 若最大匹配不匹配,找次大匹配
for cnt > 0 && pattern[cnt] != v {
cnt = pi[cnt - 1]
}
// 如果匹配了长度加一
if pattern[cnt] == v {
cnt++
}
pi[i] = cnt // pi[i]表示到第i个前后缀匹配的最大长度
}
cnt = 0
for i, v := range text {
// 遍历text
for cnt > 0 && pattern[cnt] != byte(v) {
cnt = pi[cnt - 1]
}
if pattern[cnt] == byte(v) {
cnt++
}
// 若匹配长度就是m,成功
if cnt == m {
pos = append(pos, i - m + 1)
cnt = pi[cnt - 1] // 回退一个,为后面的做准备
}
}
return
}