344.反转字符串
编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 char[] 的形式给出。
不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。
你可以假设数组中的所有字符都是 ASCII 码表中的可打印字符。
示例 1:
输入:["h","e","l","l","o"]
输出:["o","l","l","e","h"]
示例 2:
输入:["H","a","n","n","a","h"]
输出:["h","a","n","n","a","H"]
解题思路:
- 双指针:定义两个指针一前一后,将指向的元素两两交换
- 对于使用for循环,每个指针移动的范围小于数组长度的一半(奇数个偶数个均如此) [ i < len/2 ]
- 对于使用while循环,当两个指针相遇时(奇数个,left = right),或两个指针交错时(偶数个,left > right)退出循环,即循环条件是:while(left < right)
class Solution {
public void reverseString(char[] s) {
//双指针,一前一后,两两交换
int left = 0;
int right = s.length - 1;
//当两个指针相遇或交错时退出循环
while(left < right){
//交换
s[left] ^= s[right];//构造 a ^ b 的结果,并放在 a 中
s[right] ^= s[left];//将 a ^ b 这一结果再 ^ b ,存入b中,此时 b = a, a = a ^ b
s[left] ^= s[right];//a ^ b 的结果再 ^ a ,存入 a 中,此时 b = a, a = b 完成交换
//移动两个指针
left++;
right--;
}
}
}
541. 反转字符串II
给定一个字符串 s 和一个整数 k,从字符串开头算起, 每计数至 2k 个字符,就反转这 2k 个字符中的前 k 个字符。
如果剩余字符少于 k 个,则将剩余字符全部反转。
如果剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符,其余字符保持原样。
示例:
输入: s = "abcdefg", k = 2
输出: "bacdfeg"
解题思路:
- 按照传统的固定思维,遍历数组时,i每次只移动一个位置(即i++),如果本题这样逐个遍历,需要写很多逻辑代码,再搞一个计数器,来统计2k,再统计前k个字符,很麻烦
- 其实在遍历字符串的过程中,只要让 i += (2 * k),i 每次移动 2 * k 就可以了,然后判断是否需要有反转的区间。
- 需要反转的部分也就是每个2 * k 区间的起点,这样写,程序会高效很多
- 所以当需要固定规律一段一段去处理字符串的时候,要想想在for循环的表达式上做做文章。
题目反转规则具体分析:
- 1. 每隔 2k 个字符的前 k 个字符进行反转
- 2. 剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符
- 3. 剩余字符少于 k 个,则将剩余字符全部反 转
- 三条规则可转换为一个判断条件:i + k < str.length()
- 若满足,说明当前 i 的位置加上k后还没有超出数组长度,反转 i ~( i + k -1),包含条件1,2
- 若不满足,说明 i+k 已经超过数组长度,即剩余字符不足k个,反转 i ~(str.length()-1 )
易错点:
String
在 Java 中是不可变的,意味着不能直接修改String
对象的内容,需要将字符串转换为字符数组后作为参数传入 reverse 方法i + k - 1 是前k个字符的最后一个字符的下标
class Solution {
public String reverseStr(String s, int k) {
char[] ch = s.toCharArray(); // 将字符串转换为字符数组
// 每次移动 2*k 个位置
for (int i = 0; i < ch.length; i += (2 * k)) {
// 每个2 * k 区间的起点就是反转的起点
// 判断从起点开始往后是否有k个字符
if (i + k < ch.length) {
// 有k个
// 注意:i + k - 1 是前k个字符的最后一个字符
reverse(ch, i, i + k - 1);
} else {
// 不足k个
reverse(ch, i, ch.length - 1);
}
}
return ne