题目一:344. 反转字符串
解法1:单指针法
class Solution {
public:
void reverseString(vector<char>& s) {
int n = s.size();
if (n < 2) return;
int left = 0;
while (left < n / 2) {
char tmp = s[left];
s[left] = s[n - left - 1];
s[n - left - 1] = tmp;
left++;
}
}
};
特点:
- 使用单个指针
left - 通过
n - left - 1计算对称位置 - 遍历到数组中间即可
解法2:双指针法(更直观)
class Solution {
public:
void reverseString(vector<char>& s) {
if (s.size() < 2) return;
int left = 0, right = s.size() - 1;
while (left < right) {
char tmp = s[left];
s[left] = s[right];
s[right] = tmp;
left++;
right--;
}
}
};
特点:
- 使用双指针
left和right - 逻辑更清晰直观
- 交换直到指针相遇
题目二:541. 反转字符串 II
解法:分段反转
class Solution {
public:
string reverseStr(string s, int k) {
for (int i = 0; i < s.size(); i += (k * 2)) {
// 需要反转的区间: [i, i+k-1]
if (i + k <= s.size()) {
reverse(s.begin() + i, s.begin() + i + k); // 反转前k个
continue;
}
reverse(s.begin() + i, s.end()); // 剩余不足k个,全部反转
}
return s;
}
};
算法思路详解
反转字符串 II 的执行逻辑:
输入: s = "abcdefg", k = 2
分段处理:
i=0: 反转[0,1] → "bacdefg"
i=4: 反转[4,5] → "bacdfeg"
i=8: 超出范围,结束
结果: "bacdfeg"
规则总结:
- 每
2k个字符为一组 - 每组反转前
k个字符 - 剩余字符少于
k个时,全部反转
核心技巧对比
| 技巧 | 适用场景 | 时间复杂度 | 空间复杂度 |
|---|---|---|---|
| 单指针 | 简单反转、对称操作 | O(n) | O(1) |
| 双指针 | 双向遍历、交换操作 | O(n) | O(1) |
| 分段反转 | 固定间隔反转 | O(n) | O(1) |
关键优化点
反转字符串的交换优化:
// 更简洁的交换写法
swap(s[left], s[right]);
// 或者使用异或交换(不推荐,可读性差)
s[left] ^= s[right];
s[right] ^= s[left];
s[left] ^= s[right];
反转字符串 II 的边界处理:
// 更简洁的写法
for (int i = 0; i < s.length(); i += 2 * k) {
int end = min(i + k, (int)s.length());
reverse(s.begin() + i, s.begin() + end);
}
扩展应用
自定义反转函数:
void myReverse(vector<char>& s, int start, int end) {
while (start < end) {
swap(s[start], s[end]);
start++;
end--;
}
}
// 在反转字符串II中使用
if (i + k <= s.size()) {
myReverse(s, i, i + k - 1);
}
性能分析
反转字符串:
- 两种解法性能相同
- 双指针法更易理解和维护
反转字符串 II:
- 关键在正确的区间计算
- 注意边界条件的处理
记忆要点
-
双指针模板:
int left = 0, right = n - 1;
while (left < right) {
swap(s[left], s[right]);
left++; right--;
} -
分段反转模板:
for (int i = 0; i < n; i += 2*k) {
reverse(s, i, min(i + k, n));
}