小伙伴们共勉~
***KPM算法***
核心思想是:当某个字符不匹配时,不需要重新从头开始匹配,而是利用已经部分匹配的结果,通过一个 部分匹配表(next 数组) 来跳过那些已经比较过的字符,从而减少不必要的重复计算。
151.翻转字符串里的单词
解题思路:step1: strip() 把左右多余空格删除 step2: 反转整个字符串 step3: 把每个空格前的单词转回去
class Solution:
def reverseWords(self, s: str) -> str:
s = s.strip()
s = s[::-1]
s = ''.join(word[::-1] for word in s.split())
return s
解题思路:把string变成单词,交换左右位置
# 使用 ' ' 作为分隔符将单词列表拼接成字符串
class Solution:
def reverseWords(self, s: str) -> str:
s = s.strip()
words = s.split()
left, right = 0, len(words)-1
while left < right:
words[left], words[right] = words[right], words[left]
left += 1
right -=1
return ' '.join(words)
解题思路:直接把string变成list words,反转所有位置。
最后用[::-1] 和 reversed() 都可以
• 时间复杂度:O(n),其中 n 是字符串 s 的长度。split() 和 join() 都是 O(n) 的操作。
• 空间复杂度:O(n),用于存储分割后的单词列表和反转后的字符串。
class Solution:
def reverseWords(self, s: str) -> str:
words = s.split()
#words = words[::-1]
#return ' '.join(words)
return ' '.join(reversed(words))
卡码网:55.右旋转字符串
解题思路:对于python可能有点作弊?
k = int(input())
s = input()
print( s[-k:] + s[:-k] )
28. 实现 strStr()
解题思路:直接比较切片内容是否一致
class Solution:
def strStr(self, haystack: str, needle: str) -> int:
if needle == '':
return 0
for i in range(len(haystack)+1-len(needle)):
#只留足够needle空位的长度
if haystack[i:i+len(needle)] == needle:
return i
return -1
解题思路:KMP算法解法(看了又看还是一知半解)
class Solution:
def getNext(self, next: List[int], s: str) -> None:
# 构建 next 数组,用于存储模式串的部分匹配信息
j = 0 # j 用来表示前缀的长度
next[0] = 0 # 第一个字符的 next 值为 0
for i in range(1, len(s)): # 从第二个字符开始计算 next 数组
while j > 0 and s[i] != s[j]:
j = next[j - 1] # 回退到前一个最长前缀的位置
if s[i] == s[j]: # 如果字符匹配,前缀长度增加
j += 1
next[i] = j # 记录当前字符的 next 值
def strStr(self, haystack: str, needle: str) -> int:
# 特殊情况:如果 needle 为空,返回 0
if len(needle) == 0:
return 0
# 生成模式串 needle 的 next 数组
next = [0] * len(needle)
self.getNext(next, needle)
j = 0 # 模式串的指针
for i in range(len(haystack)): # 遍历主串 haystack
while j > 0 and haystack[i] != needle[j]:
j = next[j - 1] # 不匹配时,跳到 next[j-1]
if haystack[i] == needle[j]:
j += 1 # 如果匹配,模式串指针 j 向右移动
if j == len(needle): # 完全匹配时返回匹配的起始位置
return i - len(needle) + 1
return -1 # 没有匹配到,返回 -1
459.重复的子字符串
解题思路:构造字符串
1. s + s:将字符串 s 复制两份。例如,如果 s = "abcabc",那么 s + s = "abcabcabcabc"。
2. [1:-1]:去掉 s + s 的第一个和最后一个字符。例如,s + s = "abcabcabcabc" 变成 "bcabcabcab"。
3. find(s):检查去掉首尾字符的字符串中是否还能找到原字符串 s。如果能找到,说明 s 是由某个子串重复构成的,返回 True;否则返回 False。
class Solution:
def repeatedSubstringPattern(self, s: str) -> bool:
# 将字符串 s 复制两份,去掉头尾,判断 s 是否在中间
return (s + s)[1:-1].find(s) != -1
解题思路:KMP解法***
输入: "abab"
next 数组: [0, 0, 1, 2] # 表示前缀 "ab" 是一个长度为 2 的重复子串
解释: 字符串长度 4,前缀长度 2,可以被整除,返回 True
输入: "aba"
next 数组: [0, 0, 1] # 无法被子串重复多次构成
解释: 返回 False
class Solution:
def repeatedSubstringPattern(self, s: str) -> bool:
if len(s) == 0:
return False # 边界条件:空字符串直接返回 False
# 构建 next 数组,用于存储前缀的匹配情况
next = [0] * len(s)
self.getNext(next, s)
# 判断条件:
# 1. next[-1] != 0:表示存在相同前后缀
# 2. len(s) % (len(s) - next[-1]) == 0:表示字符串的长度能被重复子串的长度整除
if next[-1] != 0 and len(s) % (len(s) - next[-1]) == 0:
return True
return False
# 计算 next 数组
def getNext(self, next, s: str):
next[0] = 0 # 初始化,第一个字符的前缀长度为 0
j = 0 # j 用来表示前缀的长度
# 从第二个字符开始,逐步构建 next 数组
for i in range(1, len(s)):
# 当不匹配时,通过 next 数组回溯,找到可以继续匹配的前缀
while j > 0 and s[i] != s[j]:
j = next[j - 1] # 回到上一个最长前缀的长度
# 如果匹配上了,前缀长度 j + 1
if s[i] == s[j]:
j += 1
next[i] = j # 将当前匹配的前缀长度记录在 next 数组中