894 字
4 分钟
代码随想录算法训练营第八天 | 字符串 Part02
字符串 Part02 笔记
151. 翻转字符串里的单词
class Solution: def reverseWords(self, s: str) -> str: # 将字符串按空格分割成单词列表 s = s.split() left, right = 0, len(s) - 1 # 使用双指针反转单词列表 while left < right: s[left], s[right] = s[right], s[left] left += 1 right -= 1 return ' '.join(s)
卡码网:55. 右旋转字符串
import sysinput = sys.stdin.read
# 右旋转字符串,当字符串长度小于旋转次数时,实际旋转次数为长度取模def main(): data = input().split() num = int(data[0]) s = data[1] length = len(s) num = num % length res = [] res.append(s[length - num:]) res.append(s[:length - num]) print(''.join(res))
if __name__ == "__main__": main()
KMP 算法
- KMP(Knuth-Morris-Pratt)算法是一种高效的字符串匹配算法。
- 通过构建 部分匹配表(前缀表),避免重复匹配字符,从而提升搜索效率。
- 时间复杂度:O(n + m),其中 n 为文本串长度,m 为模式串长度。
应用场景
-
✅ 在大文本中查找子串
- 最基础的用途,替代暴力匹配。
-
✅ 实现
strStr()
函数- LeetCode 28,查找子串首次出现的位置。
-
✅ 检测字符串是否由重复子串组成
- LeetCode 459,判断字符串是否能通过子串重复构成。
-
✅ 字符串周期性检测
- 判断字符串的最小循环节,比如 DNA 重复序列。
-
✅ 最小字符串构造问题
- 构造最短的重复串,使得一个字符串成为其前缀或后缀。
-
✅ 前后缀匹配、构建自动机状态转移表
- KMP 中的
next
数组本质就是一种状态机转移的前缀优化,常用于构建有限状态机(FSM)模型。
- KMP 中的
-
✅ 字符串压缩 / 编码
- 如在数据压缩算法中,寻找重复模式进行压缩(与 Z-algorithm、Boyer-Moore 可组合)。
-
✅ 回文串构造与检测(改造版)
- 例:添加最少字符使字符串变为回文(可将
rev(s) + "#" + s
套用 KMP)。
- 例:添加最少字符使字符串变为回文(可将
KMP 算法模板
# 获取模式串的前缀表(部分匹配表)def getNext(s): next = [0] length = 0 i = 1 while i < len(s): if s[i] == s[length]: length += 1 next.append(length) i += 1 else: if length == 0: next.append(0) i += 1 else: length = next[length - 1] return next
# 主函数,查找模式串在文本串中出现的位置def strStr(string, pattern): next = getNext(pattern) i, j = 0, 0 while i < len(string): if string[i] == pattern[j]: i += 1 j += 1 elif j > 0: j = next[j - 1] else: i += 1 if j == len(pattern): return i - j return -1
28. 实现 strStr()
class Solution: def strStr(self, haystack: str, needle: str) -> int: next = self.getNext(needle) i, j = 0, 0 while i < len(haystack): if haystack[i] == needle[j]: i += 1 j += 1 # 如果 j 达到 needle 的长度,说明找到了匹配 if j == len(needle): return i - j elif j > 0: j = next[j - 1] else: i += 1 # 如果 j 没有达到 needle 的长度,说明没有找到匹配 return -1
def getNext(self, s): next = [0] length = 0 i = 1 while i < len(s): if s[i] == s[length]: length += 1 next.append(length) i += 1 else: if length == 0: next.append(0) i += 1 else: length = next[length - 1] return next
459. 重复的子字符串
class Solution: def repeatedSubstringPattern(self, s: str) -> bool: next = self.getNext(s) n = len(s) # 如果 next 数组的最后一个值大于 0,且 n 能被 n - next[-1] 整除,则说明存在重复的子字符串 return next[-1] > 0 and n % (n - next[-1]) == 0
def getNext(self, s): next = [0] length = 0 i = 1 while i < len(s): if s[length] == s[i]: i += 1 length += 1 next.append(length) else: if length == 0: next.append(0) i += 1 else: length = next[length - 1] return next
代码随想录算法训练营第八天 | 字符串 Part02
https://fuwari.vercel.app/posts/code_musings_day_eight/