字符串处理是算法训练中最基础也最常考的知识点之一。作为训练营的第八天内容,这个专题主要聚焦字符串的三大核心操作:反转、替换和匹配。我们先从最基础的概念讲起——在计算机中,字符串本质上是一个字符数组,这使得我们可以通过索引直接访问任意位置的字符。
重要提示:不同语言对字符串的实现方式不同,比如Python的字符串是不可变对象,而C++的string是可变的,这个特性会直接影响算法实现的效率。
新手最容易忽视的是字符串拼接操作的时间复杂度。以Java为例:
java复制String s = "";
for (int i = 0; i < 10000; i++) {
s += "a"; // 实际时间复杂度是O(n²)
}
正确的做法是使用StringBuilder,这样时间复杂度才是线性的O(n)。类似的情况也存在于Python中,频繁拼接字符串应该用"".join(list)的方式。
最经典的反转字符串方法就是双指针法,时间复杂度O(n),空间复杂度O(1):
python复制def reverseString(s: list) -> None:
left, right = 0, len(s) - 1
while left < right:
s[left], s[right] = s[right], s[left]
left += 1
right -= 1
这里有个细节需要注意:参数类型是list而不是str,因为Python的字符串不可变,需要先转为列表操作。
虽然递归写法看起来很优雅:
python复制def reverse(s):
if len(s) <= 1:
return s
return reverse(s[1:]) + s[0]
但实际上这种写法的时间复杂度是O(n²),因为每次切片操作s[1:]都需要O(n)时间,而且递归深度会导致栈空间问题。
在处理大字符串时,可以考虑以下优化:
LeetCode题目:将字符串中的每个空格替换成"%20"。看似简单,但有几种不同的解法:
暴力解法:直接使用语言内置的replace方法,但面试时不建议这么做。
标准解法:
python复制def replaceSpace(s: str) -> str:
counter = s.count(' ')
res = list(s)
res.extend([' '] * counter * 2)
left, right = len(s) - 1, len(res) - 1
while left >= 0:
if res[left] != ' ':
res[right] = res[left]
right -= 1
else:
res[right-2:right+1] = '%20'
right -= 3
left -= 1
return ''.join(res)
KMP算法通过预处理模式串,构建next数组来避免回溯,将时间复杂度从O(mn)优化到O(m+n)。
next数组构建关键点:
python复制def getNext(p: str):
next = [0] * len(p)
j = 0
for i in range(1, len(p)):
while j > 0 and p[i] != p[j]:
j = next[j-1]
if p[i] == p[j]:
j += 1
next[i] = j
return next
字符串问题最容易出错的就是边界条件:
对于每个题目,建议先自己实现,然后对比不同解法的优劣。我个人的经验是,字符串问题往往有多种解法,但最优解通常需要考虑字符串的底层实现特性。