LeetCode 28 KMP next数组
这题的难度是一个easy,可能KMP算法已经人尽皆知了吧。
KMP
有关KMP和暴力匹配,简单对比一下
S : ABCDABCABCDABCD
P : ABCDABD
现在发现了匹配失败
暴力法:P后移一位
S : ABCDABEABCDABCD
P : ABCDABD
匹配完耗时
O
(
M
∗
N
)
O(M*N)
O(M∗N)
KMP:后移next位
S : ABCDABEABCDABCD
P : ABCDABD
匹配完耗时
O
(
M
+
N
)
O(M+N)
O(M+N)
区别就是,暴力法匹配失败后pattern后移一位,KMP匹配失败后pattern后羿next[j]位
S : ABCDABCABCDABCD
P : ABCDABD
这里就不解释KMP了,网上一大堆
next数组
S : ABCDABEABCDABCD
P : ABCDABD
在匹配失败后,P的前6个字母是匹配成功的,这时p里面的字符D会指向字符C
-1 | 0 | 0 | 0 | -1 | 0 | 2 |
---|---|---|---|---|---|---|
A | B | C | D | A | B | D |
分析
上面这个next数组,如果第一个A就匹配失败,从头再来,如果第二个D匹配失败,D前面的AB一定匹配成功,所以D会指向C,下标为2的字符
code
class Solution:
def strStr(self, s1: str, s2: str) -> int:
nextn = [0] * len(s2)
return self.kmp(s1, s2, nextn)
# print(nextn)
def kmp(self, s1: str, s2: str, nextn: list) -> int:
if not s2:
return 0
# 求s1中s2第一次出现的位置
i, j = 0, 0
k, ans = -1, 0
nextn[0] = -1
lens2 = len(s2)
# 先生成next数组,这个过程就是那s2匹配S2它自己
while j < lens2:
while k != -1 and s2[j] != s2[k]:
k = nextn[k]
j += 1
k += 1
if j < lens2 and k < lens2:
if s2[j] != s2[k]:
nextn[j] = k
else:
nextn[j] = nextn[k]
# end_while
# 匹配过程
j = 0
while i < len(s1):
if j != -1 and j == lens2:
return i - j
while j != -1 and s1[i] != s2[j]:
j = nextn[j]
i += 1
j += 1
#end_while
if j == lens2:
return i - j
else:
return -1
总结
KMP就是充分利用已经匹配成功的前缀,来跳过已知必定失败的方案
欢迎一起来参与leetcode刷题项目
刷题的GitHub: github链接.