本题太痛了,想了四天,给KMP跪了
给你两个字符串 haystack
和 needle
,请你在 haystack
字符串中找出 needle
字符串的第一个匹配项的下标(下标从 0 开始)。如果 needle
不是 haystack
的一部分,则返回 -1
。
class Solution:
# # KMP
# def getNext(self, s):
# nextt = [0] * len(s)
# j = 0
# for i in range(1, len(s)):
# if s[i] == s[j]:
# j += 1
# nextt[i] = j
# while j > 0 and s[i] != s[j]:
# j = nextt[j - 1]
# return nextt
# 以上为错误版本
# 以下为正确版本
# 差就差在for循环内if和while的先后顺序
# KMP
def getNext(self, s):
nextt = [0] * len(s)
j = 0
for i in range(1, len(s)):
while j > 0 and s[i] != s[j]:
j = nextt[j - 1]
if s[i] == s[j]:
j += 1
nextt[i] = j
# 必须先判断不等再判断相等。先while再if。否则 若needle是'abab',本来next应该是[0012],错误版本得到的是[0010]
# 原因在于判断s[i] == s[j]时,判断到j0(a) i2(a)相等,下一步是j自增变j1(b),然后next[2]=1
# 然后本应i自增变i3(b)然后进入j1(b)和i3(b)相等的if判断,但错误版本直接进入j1(b)和i2(a)不等的while判断了。
return nextt
def strStr(self, haystack: str, needle: str) -> int:
nextt = self.getNext(needle)
i = 0
j = 0
if len(haystack) < len(needle):
return -1
while i < len(haystack):
while j > 0 and haystack[i] != needle[j]:
# while j > 0 and needle[j]: # 这他妈反而能通过55/79 为何
j = nextt[j - 1]
# 字母不同的时候就往回退 此时i不动,j一直退,直到j退到0跳出循环,或者遇到字母相同的情况
if haystack[i] == needle[j]:
i += 1
j += 1
# 字母相同的时候就往前走 此时i和j同步往前走
if j == len(nextt):
return i -len(nextt)
# 当j走完时说明得到这样的字符串了,返回i在第一个匹配项的下标
if j == 0 and i < len(haystack):
i += 1
# 当j回退到0时说明本次匹配尝试失败,i自增直到遇到下一个匹配项或字符串结束
# 匹配成功时j才自增,匹配失败时j回退,未找到第一个匹配项时j一直在0索引处
return -1