编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。
不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。
示例 1
输入:s = ["h","e","l","l","o"]
输出:["o","l","l","e","h"]
示例 2
输入:s = ["H","a","n","n","a","h"]
输出:["h","a","n","n","a","H"]
提示
-
1 <= s.length <= 10^5
-
s[i] 都是 ASCII 码表中的可打印字符
解题思路
这是一道经典的双指针问题。由于题目要求原地反转且使用O(1)的额外空间,最优解法就是使用双指针技术。
核心思路
- 设置两个指针:left指向数组开头,right指向数组末尾
- 交换left和right位置的字符
- left向右移动,right向左移动
- 重复步骤2-3,直到left >= right
图解过程
以示例1为例:["h","e","l","l","o"]
初始状态: ["h","e","l","l","o"]
↑ ↑
left right
第1次交换: ["o","e","l","l","h"]
↑ ↑
left right
第2次交换: ["o","l","l","e","h"]
↑
left,right重合,结束
Java实现
class Solution {
public void reverseString(char[] s) {
// 双指针法
int left = 0;
int right = s.length - 1;
// 当左指针小于右指针时继续交换
while (left < right) {
// 交换左右指针位置的字符
char temp = s[left];
s[left] = s[right];
s[right] = temp;
// 移动指针
left++;
right--;
}
}
}
Java优化版本(使用异或运算)
class Solution {
public void reverseString(char[] s) {
int left = 0;
int right = s.length - 1;
while (left < right) {
// 使用异或运算交换,无需临时变量
s[left] ^= s[right];
s[right] ^= s[left];
s[left] ^= s[right];
left++;
right--;
}
}
}
C#实现
public class Solution {
public void ReverseString(char[] s) {
// 双指针法
int left = 0;
int right = s.Length - 1;
// 当左指针小于右指针时继续交换
while (left < right) {
// 交换左右指针位置的字符
char temp = s[left];
s[left] = s[right];
s[right] = temp;
// 移动指针
left++;
right--;
}
}
}
C#优化版本(使用元组交换)
public class Solution {
public void ReverseString(char[] s) {
int left = 0;
int right = s.Length - 1;
while (left < right) {
// C# 7.0+ 元组交换语法
(s[left], s[right]) = (s[right], s[left]);
left++;
right--;
}
}
}
复杂度分析
- 时间复杂度:O(n),其中n是字符数组的长度。需要遍历数组的一半进行交换操作。
- 空间复杂度:O(1),只使用了常数个额外变量(指针和临时变量)。