28. 找出字符串中第一个匹配项的下标 - 力扣(LeetCode)
class Solution:
def getNext(self, needle:str):
j = -1
next = [0] * len(needle)
next[0] = j
for i in range(1, len(needle)):
while j >= 0 and needle[j+1] != needle[i]:
j = next[j]
if needle[j+1] == needle[i]:
j += 1
next[i] = j
return next
def strStr(self, haystack: str, needle: str) -> int:
next = self.getNext(needle)
j = -1
for i in range(len(haystack)):
while j >= 0 and haystack[i] != needle[j+1]:
j = next[j]
if haystack[i] == needle[j+1]:
j += 1
if j == len(needle) - 1:
return i - len(needle) + 1
return -1
解一(思路错误)没有彻底理解KMP的next数组。next[0] = -1, next[i]表示子字符串template从第0个字符到第i个字符[0, i]的(最大重复前缀长度-1)。以字符串s = "abcabcabc"为例,我的错误思路是把next[-1]+1当作"abc"的长度,然后在s的前后掐掉"abc"、取中间部分,判断中间部分能否与"abc"匹配。但事实上next[-1]+1是"abcabc"的长度,即前后缀都是"abcabc",这是因为next不阻止前后缀的重叠,它只限制首字符(末字符)不出现在前缀(后缀)里。
class Solution:
def getNext(self, s):
j = -1
next = [0] * len(s)
next[0] = j
for i in range(1, len(s)):
while j >= 0 and s[j+1] != s[i]:
j = next[j]
if s[j+1] == s[i]:
j += 1
next[i] = j
return next
def if_match(self, s, t):
next = self.getNext(t)
j = -1
for i in range(len(s)):
while j >= 0 and t[j+1] != s[i]:
j = next[j]
if t[j+1] == s[i]:
j += 1
if j == len(t) - 1:
return True
return False
def repeatedSubstringPattern(self, s: str) -> bool:
maxpre = self.getNext(s)[-1] + 1
if len(s) // 2 != maxpre or len(s) % 2:
t = s[maxpre : (len(s)-maxpre)]
s = s[:maxpre]
return self.if_match(s, t)
return True
解二:如果s能够由它的字串重复构成,那么s+s掐掉头尾字符,也能够与s匹配,否则s不符合要求。
class Solution:
def getNext(self, s):
j = -1
next = [0] * len(s)
next[0] = j
for i in range(1, len(s)):
while j >= 0 and s[j+1] != s[i]:
j = next[j]
if s[j+1] == s[i]:
j += 1
next[i] = j
return next
def repeatedSubstringPattern(self, s: str) -> bool:
n = len(s)
s2 = (s + s)[1 : 2*n-1]
next = self.getNext(s)
j = -1
for i in range(len(s2)):
while j >=0 and s2[i] != s[j+1]:
j = next[j]
if s2[i] == s[j+1]:
j += 1
if j == len(s) - 1:
return True
return False