1. 代码随想录算法训练营Day09内容概览
作为一名参加过多个算法训练营的程序员,我深知系统化学习的重要性。代码随想录算法训练营Day09主要聚焦于字符串相关的算法题目,这是许多初学者容易忽视但实际上非常重要的基础部分。字符串处理在算法面试中出现的频率极高,据统计约占LeetCode题库的30%以上。
Day09的典型训练内容包括:
- 字符串反转类问题(如344.反转字符串)
- 替换空格问题(剑指Offer 05)
- 翻转字符串里的单词(151.翻转字符串里的单词)
- 左旋转字符串(剑指Offer 58-II)
这些题目看似简单,但要做到bug-free(一次写对)并不容易。我在第一次参加训练时,就因为在处理字符串边界条件时考虑不周,导致多个测试用例失败。
2. 字符串反转的三种实现方式
2.1 双指针法:最优雅的解决方案
对于344.反转字符串这道经典题目,双指针法是最推荐的解法。它的时间复杂度为O(n),空间复杂度为O(1),效率极高。
python复制def reverseString(s: List[str]) -> None:
left, right = 0, len(s) - 1
while left < right:
s[left], s[right] = s[right], s[left]
left += 1
right -= 1
关键点在于:
- 不需要返回值,直接原地修改输入数组
- 循环条件是left < right,不是<=,避免不必要的中间元素交换
- Python中字符串不可变,所以题目特意给出字符列表
注意:在实际面试中,一定要先确认输入输出格式。有些面试官会要求返回新字符串而非原地修改。
2.2 递归解法:理解分治思想
虽然递归解法在效率上不如双指针,但有助于理解分治思想:
python复制def reverseString(s: List[str]) -> None:
def helper(left, right):
if left >= right:
return
s[left], s[right] = s[right], s[left]
helper(left + 1, right - 1)
helper(0, len(s) - 1)
递归深度为n/2,空间复杂度变为O(n)(因为调用栈)。这种方法在实际工程中不推荐,但在训练营中值得尝试,可以加深对递归的理解。
2.3 使用切片语法(Python特有)
Python中可以使用简洁的切片语法,但这通常不是面试官想要的答案:
python复制s[:] = s[::-1] # 注意要用s[:]而不是s,确保原地修改
这种方法虽然简洁,但隐藏了算法细节,在训练营中应该优先掌握前两种方法。
3. 字符串替换问题的核心技巧
3.1 剑指Offer05:替换空格
题目要求将字符串中的每个空格替换为"%20"。看似简单,但有几种不同的处理思路:
方法一:直接使用内置函数
python复制def replaceSpace(s: str) -> str:
return s.replace(' ', '%20')
这种方法虽然简洁,但完全避开了算法考察点,在训练营中不建议直接使用。
方法二:列表构建法(推荐)
python复制def replaceSpace(s: str) -> str:
res = []
for c in s:
if c == ' ':
res.append('%20')
else:
res.append(c)
return ''.join(res)
这种方法的时间复杂度为O(n),空间复杂度为O(n)。使用列表而不是直接拼接字符串,是因为在Python中字符串是不可变对象,每次拼接都会创建新对象,效率低下。
方法三:双指针法(C++风格)
如果题目给定的是字符数组且足够大(如C++场景),可以从后向前填充:
python复制def replaceSpace(s: str) -> str:
# 假设s是足够大的字符数组
old_len = len(s)
space_count = s.count(' ')
s += [''] * (space_count * 2) # 每个空格多需要2个位置
new_len = len(s)
# 从后向前填充
i, j = old_len - 1, new_len - 1
while i >= 0:
if s[i] == ' ':
s[j-2:j+1] = '%20'
j -= 3
else:
s[j] = s[i]
j -= 1
i -= 1
return ''.join(s)
这种方法在Python中不太自然,但有助于理解C++等语言中的实现方式。
4. 翻转字符串里的单词(151题)
这道题比简单反转要复杂得多,需要考虑:
- 去除首尾空格
- 处理单词间多个空格
- 保持单词顺序但反转整体顺序
4.1 使用内置函数的方法
python复制def reverseWords(s: str) -> str:
return ' '.join(reversed(s.split()))
虽然简洁,但同样避开了算法考察点。
4.2 手动实现全流程
完整的手动实现可以分为三步:
- 去除多余空格
- 反转整个字符串
- 反转每个单词
python复制def reverseWords(s: str) -> str:
# 1. 去除多余空格
def trim_spaces(s):
left, right = 0, len(s) - 1
# 去掉首尾空格
while left <= right and s[left] == ' ':
left += 1
while left <= right and s[right] == ' ':
right -= 1
# 去掉中间多余空格
output = []
while left <= right:
if s[left] != ' ':
output.append(s[left])
elif output[-1] != ' ': # 只保留一个空格
output.append(s[left])
left += 1
return output
# 2. 反转字符数组
def reverse(l, left, right):
while left < right:
l[left], l[right] = l[right], l[left]
left += 1
right -= 1
# 3. 反转每个单词
def reverse_each_word(l):
start = end = 0
n = len(l)
while start < n:
while end < n and l[end] != ' ':
end += 1
reverse(l, start, end - 1)
start = end + 1
end += 1
l = trim_spaces(s)
reverse(l, 0, len(l) - 1)
reverse_each_word(l)
return ''.join(l)
这个实现虽然较长,但完整展示了处理字符串问题的典型思路:先清理数据,再整体处理,最后局部处理。
5. 左旋转字符串(剑指Offer58-II)
题目要求将字符串前面的n个字符移到末尾。例如输入"abcdefg"和k=2,输出"cdefgab"。
5.1 切片法
Python中可以直接使用切片:
python复制def reverseLeftWords(s: str, n: int) -> str:
return s[n:] + s[:n]
5.2 反转三次法
更通用的解法是先反转前n个字符,再反转剩下的字符,最后反转整个字符串:
python复制def reverseLeftWords(s: str, n: int) -> str:
def reverse_sub(l, left, right):
while left < right:
l[left], l[right] = l[right], l[left]
left += 1
right -= 1
l = list(s)
reverse_sub(l, 0, n - 1)
reverse_sub(l, n, len(l) - 1)
reverse_sub(l, 0, len(l) - 1)
return ''.join(l)
这种方法虽然看起来复杂,但在某些语言(如C++)中更高效,且不需要额外空间。
6. 字符串算法常见陷阱与调试技巧
在训练营实践中,我发现字符串问题有几个常见陷阱:
-
边界条件处理:空字符串、全空格字符串、只有一个字符等情况经常被忽略。例如在反转字符串时,忘记处理空字符串会导致索引越界。
-
可变与不可变类型:Python中字符串是不可变的,直接修改会创建新对象。而题目有时要求原地修改(如344题给出的是列表),需要特别注意。
-
空格处理:多个连续空格、首尾空格等情况需要特别处理。在151题中,我最初没有处理好多个空格的情况,导致输出结果不正确。
调试技巧:
- 对于复杂的字符串操作,可以先用小例子手动模拟过程
- 打印中间结果,特别是在循环或递归中
- 使用断言检查不变量,如在反转过程中检查字符串长度是否保持不变
7. 训练营Day09的延伸学习建议
完成基础题目后,可以尝试以下延伸练习:
- KMP算法:虽然Day09不涉及,但这是字符串匹配的重要算法
- 字符串排列组合问题:如567.字符串的排列
- 回文串相关问题:如5.最长回文子串
- 字符串编码解码:如394.字符串解码
在代码随想录的训练体系中,Day09打下的字符串基础将为后续更复杂的算法学习做好准备。建议每天花30分钟复习当天内容,并尝试用不同方法解决同一问题。
