通过今天的学习, 了解使用 KMP算法做字符串匹配, 字符串的 next 数组定义以及实现算法。收获颇丰。
算法基础解释:第四章 字符串part02
28. 实现 strStr()
思路:未接触KMP算法之前, 第一想法是通过slicing window来判断, 逻辑很简单, 时间复杂度 O(m*n). 学习KMP之后, 发现这道题是典型的KMP算法题。 next 数组我比较习惯右移一位, next[0] = -1
难点: 先学算法在尝试实现
class Solution:
def get_next_group(self, s: str) -> List[int]:
next_list = [0] * len(s)
j = 0 # 前缀最后一位下标
i = 1 # 后缀第一位下标
while i < len(s):
if j > 0 and s[i] != s[j]:
j = next_list[j-1]
elif s[i] == s[j]:
j += 1
next_list[i] = j
i = i+1
else:
i += 1
return next_list
def strStr(self, haystack: str, needle: str) -> int:
next_list = self.get_next_group(needle)
next_list[1:] = next_list[0:-1]
next_list[0] = -1
i, j = 0, 0
while i < len(haystack):
if haystack[i] == needle[j] or j == -1:
i += 1
j += 1
else:
j = next_list[j]
if j >= len(needle):
return i-len(needle)
return -1
459.重复的子字符串
思路: 第一想法也是 brute force 把所有的substring 尝试一遍。 不过也可以巧妙的运用KMP 算法。 先计算next 数组。 如果 string 是有substring 复制n 次出来的, 那么next 数组的最后一位满足大于或等于 len(s) / 2。 并且 len(s) - next[-1] 一定可以被 len(s) 整除, 而且除数为n。
难点: 第一次提交没有考虑 len(s) - next[-1] 被 len(s) 整除的情况, 导致有case 出错。
class Solution:
def get_next_group(self, s: str) -> List[int]:
next_list = [0] * len(s)
j = 0 # 前缀最后一位下标
i = 1 # 后缀第一位下标
while i < len(s):
if j > 0 and s[i] != s[j]:
j = next_list[j-1]
elif s[i] == s[j]:
j += 1
next_list[i] = j
i = i+1
else:
i += 1
return next_list
def repeatedSubstringPattern(self, s: str) -> bool:
next_list = self.get_next_group(s)
if next_list[-1] < len(s) / 2:
return False
elif len(s) % (len(s)-next_list[-1]) !=0:
return False
else:
return True