Easy
题目描述
给定一个字符串 s 和一个整数 k,从字符串开头算起,每 2k 个字符反转前 k 个字符。
如果剩余字符少于 k 个,则将剩余字符全部反转。如果剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符,其余字符保持原样。
示例 1:
输入:s = "abcdefg", k = 2
输出:"bacdfeg"
示例 2:
输入:s = "abcd", k = 2
输出:"bacd"
提示:
1 <= s.length <= 10^4s仅由小写英文字母组成1 <= k <= 10^4
解题思路
这是一道模拟类题目,关键在于理解题意和找到规律。
思路分析:
- 规律观察:每
2k个字符为一组,对每组的前k个字符进行反转 - 边界处理:当剩余字符不足时,需要分情况讨论:
- 剩余字符 < k:全部反转
- k ≤ 剩余字符 < 2k:只反转前 k 个
解法一:双指针反转(推荐)
遍历字符串,每次跳跃 2k 个位置,对每个区间的前 k 个字符使用双指针进行原地反转。时间复杂度 O(n),空间复杂度 O(1)。
解法二:字符串切片 将字符串按照规律切分成段,对需要反转的段进行反转后重新拼接。实现简单但可能有额外的字符串操作开销。
核心在于正确处理边界情况和利用双指针高效反转子串。
代码实现
class Solution {
public:
string reverseStr(string s, int k) {
int n = s.length();
for (int i = 0; i < n; i += 2 * k) {
// 确定需要反转的右边界
int right = min(i + k - 1, n - 1);
// 双指针反转
int left = i;
while (left < right) {
swap(s[left], s[right]);
left++;
right--;
}
}
return s;
}
};
class Solution:
def reverseStr(self, s: str, k: int) -> str:
s = list(s) # 转换为可变列表
n = len(s)
for i in range(0, n, 2 * k):
# 确定需要反转的右边界
right = min(i + k - 1, n - 1)
# 双指针反转
left = i
while left < right:
s[left], s[right] = s[right], s[left]
left += 1
right -= 1
return ''.join(s)
public class Solution {
public string ReverseStr(string s, int k) {
char[] chars = s.ToCharArray();
int n = chars.Length;
for (int i = 0; i < n; i += 2 * k) {
// 确定需要反转的右边界
int right = Math.Min(i + k - 1, n - 1);
// 双指针反转
int left = i;
while (left < right) {
char temp = chars[left];
chars[left] = chars[right];
chars[right] = temp;
left++;
right--;
}
}
return new string(chars);
}
}
var reverseStr = function(s, k) {
const chars = s.split('');
const n = chars.length;
for (let i = 0; i < n; i += 2 * k) {
// 确定需要反转的右边界
let right = Math.min(i + k - 1, n - 1);
// 双指针反转
let left = i;
while (left < right) {
[chars[left], chars[right]] = [chars[right], chars[left]];
left++;
right--;
}
}
return chars.join('');
};
复杂度分析
| 复杂度类型 | 复杂度 | 说明 |
|---|---|---|
| 时间复杂度 | O(n) | 需要遍历整个字符串,每个字符最多被访问常数次 |
| 空间复杂度 | O(1) 或 O(n) | C++ 原地修改为 O(1);Python/JS 需要转换为可变结构为 O(n) |
相关题目
. Reverse String (Easy)
. Faulty Keyboard (Easy)