问题描述
给定一个字符串 s 和一个整数 k,从字符串开头算起,每计数至 2k 个字符,就反转这 2k 字符中的前 k 个字符。
如果剩余字符少于 k 个,则将剩余字符全部反转。
如果剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符,其余字符保持原样。
示例 1:
输入:s = “abcdefg”, k = 2
输出:“bacdfeg”
示例 2:
输入:s = “abcd”, k = 2
输出:“bacd”
思路
要解决这个问题,我们可以按照以下步骤进行:
- 遍历字符串
s
,每次处理2k
个字符。 - 对于每
2k
个字符,反转前k
个字符。 - 如果剩余字符少于
k
个,则将剩余字符全部反转。 - 如果剩余字符小于
2k
但大于或等于k
个,则反转前k
个字符,其余字符保持原样。
code
public class TestReserveStrTwo {
public static void main(String[] args) {
Solution solution = new Solution();
// 示例 1
String s1 = "abcdefg";
int k1 = 2;
System.out.println(solution.reverseStr(s1, k1)); // 输出: "bacdfeg"
// 示例 2
String s2 = "abcd";
int k2 = 2;
System.out.println(solution.reverseStr(s2, k2)); // 输出: "bacd"
}
}
class Solution {
public String reverseStr(String s, int k) {
// 将字符串 s 转换为字符数组 chars
char[] chars = s.toCharArray();
int n = chars.length;
// 遍历字符数组,每次处理 2k 个字符
for (int i = 0; i < n; i += 2 * k) {
// 对于每 2k 个字符,计算需要反转的左边界 left 和右边界 right
int left = i;
// 反转前 k 个字符,或者剩余字符的最后
int right = Math.min(i + k - 1,n - 1);
// 调用 reverse 方法反转指定范围内的字符
reverse(chars,left,right);
}
return new String(chars);
}
/**
* 使用双指针法反转字符数组中指定范围内的字符
* @param chars
* @param left
* @param right
*/
private void reverse(char[] chars, int left, int right) {
while (left < right) {
chars[left] ^= chars[right];
chars[right] ^= chars[left];
chars[left] ^= chars[right];
left++;
right--;
}
}
}
代码解释
-
reverseStr
方法:- 将字符串
s
转换为字符数组chars
。 - 遍历字符数组,每次处理
2k
个字符。 - 对于每
2k
个字符,计算需要反转的左边界left
和右边界right
。 - 调用
reverse
方法反转指定范围内的字符。
- 将字符串
-
reverse
方法:- 使用双指针法反转字符数组中指定范围内的字符。
示例解释
-
示例 1:
- 输入:
s = "abcdefg", k = 2
- 输出:
"bacdfeg"
- 解释:
- 第一次处理
abcdefg
,反转前k=2
个字符ab
->ba
,得到bacdefg
。 - 第二次处理
cdefg
,反转前k=2
个字符cd
->dc
,得到bacdfeg
。
- 第一次处理
- 输入:
-
示例 2:
- 输入:
s = "abcd", k = 2
- 输出:
"bacd"
- 解释:
- 第一次处理
abcd
,反转前k=2
个字符ab
->ba
,得到bacd
。
- 第一次处理
- 输入: