Day09 字符串
1. 💥实现 strStr()
KMP算法经典题:解决字符串匹配的问题
暴力解决时间复杂度为O(m*n):文本串长度和模式串长度
最长相等前后缀:前缀:只包含首字母的前缀;后缀:只包含尾字母的前缀
next数组:匹配过程中遇到冲突时,指针应该回退到的位置
找到的不匹配的位置, 那么此时我们要看它的前一个字符的前缀表的数值是多少。
匹配的过程是O(n),之前还要单独生成next数组,时间复杂度是O(m)。所以整个KMP算法的时间复杂度是O(n+m)的
class Solution:
def strStr(self, haystack: str, needle: str) -> int:
def getNext(next, s):
j = -1
next[0] = j
for i in range(1, len(s)):
while j>=0 and s[i] != s[j+1]:
j = next[j]
if s[i] == s[j+1]:
j+=1
next[i] = j
# 匹配
if not needle: return 0
next = [0] * len(needle)
getNext(next, 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
2. 重复的子字符串
①移动匹配
如果字符串s由重复组合组成那么2s中间一定能找到s
class Solution:
def repeatedSubstringPattern(self, s: str) -> bool:
n = len(s)
if n <= 1:
return False
ss = s[1:] + s[:-1]
print(ss.find(s))
return ss.find(s) != -1
②KMP
class Solution:
def repeatedSubstringPattern(self, s: str) -> bool:
if len(s) == 0: return False
next = [0] * len(s)
self.getNext(next,s)
if next[-1] != -1 and len(s) % (len(s)-(next[-1]+1)) == 0:
return True
return False
def getNext(self, next, s):
j = -1
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
3. 字符串总结
- 字符串匹配:KMP算法,二刷了还是有点不太懂,实在不行就背吧,背着背着就会了
- 双指针法
- 库函数erase来移除元素,这其实是O(n^2)的操作
- kmp中:其中主要理解j=next[x]这一步最为关键!
4. 双指针回顾
- 字符串问题:定义两个指针(也可以说是索引下标),一个从字符串前面,一个从字符串后面,两个指针同时向中间移动,并交换元素。,时间复杂度是O(n)。
- 链表问题:使用快慢指针(双指针法),分别定义 fast 和 slow指针,从头结点出发,fast指针每次移动两个节点,slow指针每次移动一个节点,如果 fast 和 slow指针在途中相遇 ,说明这个链表有环
- n数之和问题:通过前后两个指针不算向中间逼近,在一个for循环下完成两个for循环的工作。