344.反转字符串
public void reverseString(char[] s) {
int i = 0, j = s.length - 1;
while (i < j) {
char temp = s[i];
s[i] = s[j];
s[j] = temp;
i++;
j--;
}
}
另外一种是用异或交换两数
public void reverseString(char[] s) {
int l = 0;
int r = s.length - 1;
while (l < r) {
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 完成交换
l++;
r--;
}
}
541. 反转字符串II
这道题目其实也是模拟,实现题目中规定的反转规则就可以了。
一些同学可能为了处理逻辑:每隔2k个字符的前k的字符,写了一堆逻辑代码或者再搞一个计数器,来统计2k,再统计前k个字符。
其实在遍历字符串的过程中,只要让 i += (2 * k),i 每次移动 2 * k 就可以了,然后判断是否需要有反转的区间。
因为要找的也就是每2 * k 区间的起点,这样写,程序会高效很多。
所以当需要固定规律一段一段去处理字符串的时候,要想想在在for循环的表达式上做做文章。
public String reverseStr(String s, int k) {
char[] arr = s.toCharArray();
for (int i = 0; i < arr.length; i += 2 * k) {
int start = i;
int end = Math.min(arr.length - 1, start + k - 1);
while (start < end) {
// char temp = arr[start];
// arr[start] = arr[end];
// arr[end] = temp;
arr[start] ^= arr[end];
arr[end] ^= arr[start];
arr[start] ^= arr[end];
start++;
end--;
}
}
return new String(arr);
}
剑指Offer 05.替换空格
解法一:额外声明一个字符串
// 解法一:声明额外的字符串
public String replaceSpace (String s) {
if (s == null) return null;
StringBuilder str = new StringBuilder();
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) == ' ') {
str.append("%20");
} else {
str.append(s.charAt(i));
}
}
return str.toString();
}
解法二:双指针
首先扩充数组到每个空格替换成"%20"之后的大小。然后从后向前替换空格,也就是双指针法,过程如下:i指向新长度的末尾,j指向旧长度的末尾。
从前向后填充就是O(n^2)的算法了,因为每次添加元素都要将添加元素之后的所有元素向后移动。其实很多数组填充类的问题,都可以先预先给数组扩容带填充后的大小,然后在从后向前进行操作。
这么做有两个好处:
- 不用申请新数组。
- 从后向前填充元素,避免了从前向后填充元素时,每次添加元素都要将添加元素之后的所有元素向后移动的问题。
//方式二:双指针法
public String replaceSpace(String s) {
if(s == null || s.length() == 0){
return s;
}
//扩充空间,空格数量2倍
StringBuilder str = new StringBuilder();
for (int i = 0; i < s.length(); i++) {
if(s.charAt(i) == ' '){
str.append(" ");
}
}
//若是没有空格直接返回
if(str.length() == 0){
return s;
}
//有空格情况 定义两个指针
int left = s.length() - 1;//左指针:指向原始字符串最后一个位置
s += str.toString();
int right = s.length()-1;//右指针:指向扩展字符串的最后一个位置
char[] chars = s.toCharArray();
while(left>=0){
if(chars[left] == ' '){
chars[right--] = '0';
chars[right--] = '2';
chars[right] = '%';
}else{
chars[right] = chars[left];
}
left--;
right--;
}
return new String(chars);
}
151.翻转字符串里的单词
定义双指针,从后往前遍历,快指针遇到空格就把当前双指针的字符加入到新字符串中,然后双指针跳转到下一个字符末尾。(我这里没有用卡尔的题解,感觉有点太多了就没看doge)
public String reverseWords(String s) {
s = s.trim();
StringBuilder str = new StringBuilder();
int i = s.length() - 1, j = i;
while (i >= 0) {
while (i >= 0 && s.charAt(i) != ' ') i--; // 快指针找到空格为止
str.append(s.substring(i + 1, j + 1) + " "); // 添加字符
while (i >= 0 && s.charAt(i) == ' ') i--; // 跳过空格
j = i; // j指向下一个字母的尾字符
}
return str.toString().trim();
}
剑指Offer58-II.左旋转字符串
public String LeftRotateString (String str, int n) {
int len = str.length();
StringBuilder sb = new StringBuilder(str);
reverseString(sb, 0, n - 1); // 反转区间为前n的子串
reverseString(sb, n, len - 1); // 反转区间为n到末尾的子串
return sb.reverse().toString(); // 反转整个字符串
}
private void reverseString(StringBuilder str, int start, int end) {
while (start < end) {
char temp = str.charAt(start);
str.setCharAt(start, str.charAt(end));
str.setCharAt(end, temp);
start++;
end--;
}
}