文章目录
一、344. 反转字符串
1. 思路分析
很基本的字符串操作,后面经常用到的reverse方法。
头尾指针交换后往中间找就是了。
2. 代码展示
class Solution {
public void reverseString(char[] s) {
int left = 0;
int right = s.length - 1;
while (left < right) {
char temp;
temp = s[left];
s[left] = s[right];
s[right] = temp;
left++;
right--;
}
}
}
二、541. 反转字符串 II
1. 思路分析
一开始写得太繁复了,其实在for循环中让i每次都加2*k是可行的,只需要加一条限制条件的约束。
本题主要是尽可能把思路逻辑简化。
- if (i + k <= c.length)
这个条件表明在下一轮“2k”中,仍然会有k个字符会反转。
我们其实可以把“如果剩余字符小于 2k 但大于或等于 k 个”以及“剩余字符恰好等于2k个”看作一个条件。 - 于是特殊情况就是“剩余字符少于 k 个”的情况,这时就应该从i开始到字符串的长度结束全部翻转即可。
2. 解法分析
最开始写的反转函数需要传入string传出string,然后时间开销高得要命。
改成了传入char[],函数内部直接修改,不用返回。一下子就0ms了。
看来对象的创建和销毁、传入传出的也很耗时间嘛。要注意一下。
3. 代码展示
class Solution {
public String reverseStr(String s, int k) {
int i = 0;
char[] c = s.toCharArray();
for (; i < c.length; i += 2 * k) {
if (i + k <= c.length) {
reverse(c, i, i + k);
}
else{
reverse(c, i, c.length);
}
}
return new String(c); // 字符数组转字符串
}
public void reverse(char[] c, int start, int end) {
end--;
while (start < end) {
char temp = c[start];
c[start] = c[end];
c[end] = temp;
start++;
end--;
}
}
}
三、卡码网:54.替换数字
1. 思路分析
Java的String是不可变数据类型,所以必须要加一层辅助空间。
没啥特别的,只是从零开始编程,又把Java程序的结构复习了一遍。
2. 解法分析
创建一个StringBuffer,狠狠地append!
3. 代码展示
import java.util.*;
class Main{
public static StringBuffer replace (String s) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) >= '0'&& s.charAt(i) <= '9') {
sb.append("number");
}
else{
sb.append(s.charAt(i));
}
}
return sb;
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String s = scanner.next();
System.out.println(replace(s));
}
}
四、151.翻转字符串里的单词
1. 思路分析
本题的难度对我来说挺难的了,我能清楚地感受到自己对于边界条件、代码细节的判断不清,以及Java字符串运用的捉襟见肘。
本题的解法思路为:
- 移除多余空格: “the sky is blue”
- 将整个字符串反转:“eulb si yks eht”
- 将每个单词反转:“blue is sky the”
解题不用总想着一步到位,分着步骤来也可以。只要每一步的时间复杂度都不高,最终的复杂度也不会高一个层级。
2. 解法分析
-
首先是“移除多余空格”。去掉头尾空格,单词之间只保留一个空格。
按照第一反应的思路,自然是找到多余空格然后删掉。我使用了StringBuffer的delete方法(左闭右开)。但是这个方法复杂度为 O ( n ) O(n) O(n),加上for循环后变成 O ( n 2 ) O(n^2) O(n2),直接给我干超时了。
不能这样干。参考 27.移除数组 的解题思路,快慢指针法,让快指针找有效元素赋给慢指针实现时间 O ( n ) O(n) O(n)空间 O ( 1 ) O(1) O(1)的数组移除算法。
我也因此深切地感受到自己对循环条件和细节把握不清,什么条件漏掉了,什么时候++了,需要改好多次才能改掉。
-
“将整个字符串反转”以及“将每个单词反转”的原理都是一样的。
都是通过自己写的reverse方法来进行反转,第一次整体,第二次局部,就OK了。
-
最后输出String,String有一个特殊的构造方法,能截取特定长度特定部分的字符数组char[]进行构造,挺贴心的。
public String(char[] value, int offset, int count)
3. 代码展示
class Solution {
public String reverseWords(String s) {
// StringBuffer sb = new StringBuffer(s); // 可变数据类型StringBuffer
// while (sb.charAt(0) == ' ')
// sb.delete(0, 0);
// // StringBuffer的delete方法,左闭右开,时间复杂度为O(n)
// while (sb.charAt(sb.length() - 1) == ' ')
// sb.delete(sb.length() - 1, sb.length() - 1);
// for (int i = 0; i < sb.length(); i++) {
// while (sb.charAt(i) == ' ' && sb.charAt(i + 1) == ' ') {
// sb.delete(i + 1, i + 1);
// }
// }// 试图整顿括号。
// 上述代码n方复杂度超时了,换成下面的
// 思路同27.移除元素,只用O(1)的复杂度原地移除,原理是快指针找有效元素赋到慢指针上,
// 其实就是把该数组前面的内存当成一个新数组存了,因为有效元素更少,所以可以这样做。
char[] c = s.toCharArray();
int slow = 0, fast = 0;
while (c.length > 0 && fast < c.length && c[fast] == ' ') {
fast++;
}// 除前导空格
for (; fast + 1 < c.length; fast++) {
if (c[fast] == ' ' && c[fast + 1] == ' ') {
// 不能用fast++,因为是for循环会++两次
continue;
}
else{
c[slow++] = c[fast];
}
}
if (c[fast] != ' ')
c[slow++] = c[fast];
int count = slow;
reverse(c, 0, count);
int left = 0, right = 0;
for (; right < count; right++) {
if (c[right] == ' ') {
reverse(c, left, right);
left = right + 1;
}
if (right == count - 1) {
reverse(c, left, right + 1);
}
}//整体反转后再局部反转
return new String(c, 0, count); // 从字符数组中选取一部分构建新的字符串的构造方法
}
// Java的参数传递:基本数据类型都是值传递,而对象都是引用传递。
// Java中,数组也是对象。
public void reverse(char[] c, int start, int end) { // 左闭右开
// 时间复杂度为O(n)
end--;
while (start < end) {
char temp = c[start];
c[start] = c[end];
c[end] = temp;
start++;
end--;
}
}
}
五、卡码网:55.右旋转字符串
1. 思路分析
整体反转+局部反转。可以实现原地反转的效果。
2. 解法分析
学到了一些Java输入的代码。
创建好Scanner对象以后,执行nextLine()方法才会读取一行输入。
3. 代码展示
import java.util.*;
public class Main {
public static void main (String[] args) {
Scanner sc = new Scanner(System.in);
String k1 = sc.nextLine();
int k = Integer.parseInt(k1);
String s = sc.nextLine();
System.out.println(turnRight(k, s));
}
static String turnRight (int k, String s) {
char[] c = s.toCharArray();
reverse(c, 0, c.length);
reverse(c, 0, k);
reverse(c, k, c.length);
return new String(c);
}
static void reverse (char[] c, int start, int end) {
end--;
while (start < end) {
char temp = c[start];
c[start++] = c[end];
c[end--] = temp;
}
}
}
六、总结
Java语法的了解真的更深了。感觉学校的课程基础略显不足。
以及基本上每道题都要使用自己写的reserve方法,随时手敲!