Reverse a String
你会得到一个由英文字母和数字组成的字符串 s。请返回一个由相同字符组成的新字符串,顺序与原字符串相反,也就是最后一个字符排在最前面,第一个字符排在最后面。每个字符都要保持原样,包括大小写。
函数
- sstring
- 要反转的字符串
- 返回值string
- s 中的字符,按相反顺序排列
约束条件
1 ≤ s.length ≤ 104s只包含英文字母(a到z、A到Z)和数字(0到9)。
示例
- 输入
- s = "Coddy2026"
- 输出
- "6202yddoC"
- 解释
- 从最后一个字符到第一个字符读取
Coddy2026:6、2、0、2,然后是y、d、d、o,最后是大写字母C。
- 输入
- s = "noon"
- 输出
- "noon"
- 解释
noon是一个回文词,所以反过来还是同一个词。外侧的两个n交换位置,然后两个o也交换位置。
- 输入
- s = "Q"
- 输出
- "Q"
- 解释
- 只有一个字符的字符串没有可交换的内容,因此会保持不变。
进阶
你会如何颠倒句子中单词的顺序,将 hello big world 变成 world big hello,同时保持每个单词中字母的顺序不变?
提示
逐个打开提示,每个都会多透露一点。
索引
0处的字符最后出现在答案中的哪个位置?索引i处的字符最后会出现在什么位置?它会移动到索引
n-1-i。第一个字符和最后一个字符交换位置,然后第二个字符和倒数第二个字符交换位置,以此类推,直到中间。将字符串复制到一个字符数组中。保留一个位于开头的索引和一个位于末尾的索引,交换这两个字符,然后让两个索引向中间移动,直到它们相遇。最后将数组重新拼接成字符串。
题解
每个字符都有固定的位置:索引 i 处的字符应放在索引 n-1-i 处。你可以按这个顺序把字符写入一个新字符串,也可以从两端开始成对交换字符。面试官通常会要求你使用交换的方法,因为同样的双指针移动也能原地反转数组并检查回文。
从后面复制字符
思路
反转后的字符串从最后一个字符开始,到第一个字符结束,所以让索引从 n-1 递减到 0,并将每个字符追加到答案中。每个字符只读取一次、写入一次:时间复杂度为 O(n),另外答案字符串占用 O(n) 空间。
可以追加到列表或字符串构建器中,并在最后拼接一次。使用 + 向不可变字符串添加一个字符时,每次都会复制整个字符串。对于 n = 10^4,大约会复制 5 × 10^7 个字符。
算法
- 为答案创建一个空列表或字符串构建器。
- 让
i从n-1递减到0。 - 将
s[i]添加到答案中。 - 将答案拼接成字符串并返回。
def reverseString(s):
result = []
for i in range(len(s) - 1, -1, -1):
result.append(s[i])
return "".join(result)使用两个指针从两端交换
思路
第一个和最后一个字符交换位置,然后第二个和倒数第二个交换位置,依此向中间推进。将 left 放在索引 0 处,将 right 放在 n-1 处,交换它们,然后让两者同时向内移动,直到相遇或交错。每次交换都会让两个字符到达最终位置,因此交换 n / 2 次就能完成任务。对于 xYz 这样的奇数长度字符串,中间的字符已经在正确的位置,不会被触碰。
交换需要一个临时变量。大多数语言无法原地修改字符串,因此你需要先将它复制到字符数组中,这会产生 O(n) 的开销。如果输入本身已经是可变数组,反转只需要 O(1) 的额外空间。
算法
- 将
s复制到字符数组中。 - 将
left = 0和right = n-1。 - 当
left < right时,交换left和right位置上的字符,然后将left加 1,并将right减 1。 - 将数组转换回字符串并返回。
def reverseString(s):
chars = list(s)
left, right = 0, len(chars) - 1
while left < right:
chars[left], chars[right] = chars[right], chars[left]
left += 1
right -= 1
return "".join(chars)
易错点和边界情况
- 让
left一直循环到n-1。过了中间位置后,每对字符都会被换回原来的位置,字符串也就恢复原样。遇到left < right时停止。 - 反向循环从
n而不是n-1开始,这会读取末尾之后的一个位置。在 Lua 和 R 中,索引从1到n。 - 在 C 中忘记添加终止符
'\0'。长度为n字节的缓冲区少了一个字节,应分配n + 1个字节。 - 交换时没有使用临时变量。执行
chars[left] = chars[right]后,原来的左侧字符就丢失了,除非你的语言可以一次交换两个值。
常见问题3
反转一个字符串的时间复杂度是多少?
反转需要 O(n) 的时间,因为每个字符都必须移动到新位置,而且每个字符只处理一次。构建新字符串需要额外的 O(n) 空间。如果字符已经存储在可变数组中,使用两个指针交换只需要额外的 O(1) 空间。
如何在不使用内置反转函数的情况下反转字符串?
将字符复制到数组中,在两端各放置一个指针,交换两个字符,然后让指针相向移动,直到它们相遇。或者,从最后一个索引开始向前遍历到第一个索引,并将每个字符追加到构建器中。这两种方法都能在一次遍历中生成反转后的字符串。
你能原地反转一个字符串吗?
只有当字符存放在可变缓冲区中时,才能这样做,例如 C、Java 或 C# 中的 char 数组,Python 中的列表,或 C++ 中的 std::string。Java、Python 和 JavaScript 中的字符串是不可变的,所以你需要先把它们复制到数组中,在数组中交换字符,再构建一个新字符串。
def reverseString(s):
# 在这里编写代码
return s测试 #1
测试 #2
测试 #3
参数
s = "Coddy2026"
预期输出
"6202yddoC"