一、反转字符串
使用双指针方法,分别从头尾往中间遍历。
public void reverseString(char[] s) {
int left = 0;
int right = s.length-1;
while(left < right){
char tmp;
tmp = s[left];
s[left] = s[right];
s[right] = tmp;
left++;
right--;
}
}
题解中使用的**异或(^)**交换两个值,这个思想我第一次接触,并在网上看到了证明过程:
x_1 = x_0 ^ y_0;
y_1 = x_1 ^ y_0 = (x_0 ^ y_0) ^ y_0 = x_0 ^ (y_0 ^y_0) = x_0 ^ 0 = x_0;
x_2 = x_1 ^ y_1 = (x_0 ^ y_0) ^ x_0 = y_0 ^ 0 = y_0;
所以,代码中的位置交换可以写成:
s[l] ^= s[r]; //构造 a ^ b 的结果,并放在 a 中
s[r] ^= s[l]; //将 a ^ b 这一结果再 ^ b ,存入b中,此时 b = a, a = a ^ b
s[l] ^= s[r]; //a ^ b 的结果再 ^ a ,存入 a 中,此时 b = a, a = b 完成交换
二、反转字符串II
这道题需要注意的点是,在进行最后一个2k(可能不足2k)小组的操作前, 需要先判断这一组的值与k的关系:<k,则右边界为数组的长度-1;>k,则有边界为k。
以下是代码部分:
public String reverseStr(String s, int k) {
char[] ch = s.toCharArray();
for(int i = 0; i < ch.length; i += 2 * k){
int start = i;
//这里是判断尾数够不够k个来取决end指针的位置
int end = Math.min(ch.length - 1, start + k - 1);
//用异或运算反转
while(start < end){
ch[start] ^= ch[end];
ch[end] ^= ch[start];
ch[start] ^= ch[end];
start++;
end--;
}
}
return new String(ch);
}
三、剑指Offer 05.替换空格
Java中由于string类型是常量,无法做修改,我的做法是定义一个等价于字符串的字符数组,然后再数组中操作。
首先,计算以下空格数量,然后定义的数组大小是——字符串长度 + 空格数量*2 。
public static String replaceSpace(String s) {
//记录s中有多少个空格
int count = 0;
for (int i = 0; i < s.length(); i++) {
int n = s.length();
if( s.charAt(i) == ' ')
count++;
}
//新生成一个字符数组,大小是原大小+count*2
char[] c = new char[s.length() + count*2];
//往新数组中填充字符
int i = 0; //新数组指针
int j = 0; //旧字符串指针
while(i < c.length){
if(s.charAt(j) != ' ') {
c[i] = s.charAt(j);
i++;
j++;
}else{
//这里第一次提交的时候出错了,因为第一行没有++,++在后运行完这一行代码再进行加的操作
c[i++] = '%';
c[i++] = '2';
c[i++] = '0';
j++;
}
}
String s2 = new String(c);
return s2;
}
四、翻转字符串里的单词
这道题的整体思路:1.删除多的空格 2.对整个数组进行反转 3.对数组中的每个单词进行反转。
在删除多的空格的时候可以运用数组中删除元素是用到的双指针思想——快指针和慢指针,快指针用于遍历旧的数组,慢指针用于往新的数组插入符合要求的元素,这里的数组指的同一个。
以下是我的代码部分,有些冗长:
public String reverseWords(String s) {
//这里+1,是因为后边有一处要额外添加一个‘ ’,防止越界
char[] c = new char[s.length()+1];
//从后往前遍历s字符串
int i = s.length()-1;
//从前往后遍历c字符数组
int j = 0;
//先把多余的空格删掉,并且将字符串整个反转(新的字符数组c最后一位可能是’ ‘)
while( i>=0 ){
//特殊处理字符串中最后一个字符,如果是空格,直接跳过
if( s.charAt(i)==' ' && i==s.length()-1) {
i--;
continue;
}
//对于空格,且前一位也是空格,则跳过
if( s.charAt(i)==' ' && s.charAt(i+1)==' '){
i--;
continue;
}
c[j] = s.charAt(i);
i--;
j++;
}
//判别新数组c的最后一个有意义的字符是否为‘ ’,若不是,则加一位‘ ’,用于后边单词反转的统一判别条件
if(c[j-1]!=' '){
c[j] = ' ';
j++;
}
int index = 0;
//记录单词的左边
int left = 0;
//记录单词的右边
int right = 0;
while( index < j ){
//不是空格,则不去反转
if(c[index] != ' '){
index++;
continue;
}
//更新right
right = index - 1;
//进行单词的反转
while(left < right){
char tmp = c[left];
c[left] = c[right];
c[right] = tmp;
left++;
right--;
}
//更新left
left = index+1;
index++;
}
//需要重新定义一个数组,因为c数组的大小是字符串的大小
char[] res = new char[j-1];
for (int l = 0; l < res.length; l++) {
res[l] = c[l];
}
String s2 = new String(res);
return s2;
}
五、剑指Offer58-II.左旋转字符串
在可以使用额外空间的情况下,还是比较容易做出来的。开辟一个新的数组暂存前n个数。
以下是代码部分:
public String reverseLeftWords(String s, int n) {
char[] c = s.toCharArray();
char[] tmp = new char[n];
int index = 0;
while(index < n){
tmp[index] = s.charAt(index);
index++;
}
int i = 0;
while (index < s.length()){
c[i] = s.charAt(index);
i++;
index++;
}
int j = 0;
while (i < c.length){
c[i] = tmp[j];
i++;
j++;
}
String s2 = new String(c);
return s2;
}
但是,当不能使用额外空间的话,就有点难度。需要用到局部反转和全局反转。
具体步骤为:
- 反转区间为前n的子串
- 反转区间为n到末尾的子串
- 反转整个字符串
以下是代码部分:
class Solution {
public String reverseLeftWords(String s, int n) {
int len=s.length();
StringBuilder sb=new StringBuilder(s);
reverseString(sb,0,n-1);
reverseString(sb,n,len-1);
return sb.reverse().toString();
}
public void reverseString(StringBuilder sb, int start, int end) {
while (start < end) {
char temp = sb.charAt(start);
sb.setCharAt(start, sb.charAt(end));
sb.setCharAt(end, temp);
start++;
end--;
}
}
}