建议: 本题是字符串基础题目,就是考察 reverse 函数的实现,同时也明确一下 平时刷题什么时候用 库函数,什么时候 不用库函数
题目链接:344.反转字符串
文章讲解/视频讲解:344.反转字符串
双指针的应用
reserve库函数的实现
明确平时刷题什么时候用 库函数,什么时候 不用库函数
class Solution {
public void reverseString(char[] s) {
int l = 0;
int r = s.length - 1;
char temp;
while(l < r){
temp = s[l];
s[l] = s[r];
s[r] = temp;
l++;
r--;
}
}
}
建议:本题又进阶了,自己先去独立做一做,然后在看题解,对代码技巧会有很深的体会。
题目链接:541. 反转字符串II
文章讲解/视频讲解:541. 反转字符串II
三种情况分别如何处理
其实在遍历字符串的过程中,当需要固定规律一段一段去处理字符串的时候,不一定要i++
这种,可以让 i += (2 * k)
,i 每次移动 2 * k
就可以了,然后判断是否需要有反转的区间。因为要找的也就是每2 * k 区间的起点,这样写,程序会高效很多。
reserve()函数左闭右开,注意边界的处理。
class Solution {
public String reverseStr(String s, int k) {
char[] ch = s.toCharArray();
for(int i = 0; i < ch.length; i+=2*k){
if(i + k <= ch.length){
reverse(ch, i, i+k-1); // 1. 剩余字符小于 2k;2. 剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符,其余字符保持原样。
}else{
reverse(ch, i, ch.length-1); // 3. 如果剩余字符少于 k 个,则将剩余字符全部反转。
}
}
return new String(ch);
}
// 定义翻转函数
public void reverse(char[] ch, int i, int j) {
for (; i < j; i++, j--) {
char temp = ch[i];
ch[i] = ch[j];
ch[j] = temp;
}
}
}
建议:对于线性数据结构,填充或者删除,后序处理会高效的多。好好体会一下。(但是对于java一定要开辟新空间,好像没什么用
题目链接:卡码网:54.替换数字
题目链接/文章讲解:卡码网:54.替换数字
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
String s = in.nextLine();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < s.length(); i++) {
if (Character.isDigit(s.charAt(i))) {
sb.append("number");
}else sb.append(s.charAt(i));
}
System.out.println(sb);
}
}
###不熟悉的基础语法知识
此时算上本题,我们已经做了七道双指针相关的题目了分别是:
27.移除元素
15.三数之和
18.四数之和
206.翻转链表
142.环形链表II
344.反转字符串
建议:这道题目基本把 刚刚做过的字符串操作 都覆盖了,不过就算知道解题思路,本题代码并不容易写,要多练一练。
题目链接:151.翻转字符串里的单词
文章讲解/视频讲解:151.翻转字符串里的单词
多余空格的删除----->整体翻转-------->每个单词翻转
视频中讲解的方法直接在原String操作,不适合java,因为String字符串一旦创建就不可改变
首先得把字符串转化成其他可变的数据结构,同时还需要在转化的过程中去除空格。
难点:多余空格的删除
// leecode官方解法1 直接用库函数
class Solution {
public String reverseWords(String s) {
// 除去开头和末尾的空白字符
s = s.trim(); // 这个底层是不是新创建了一个string空间存放处理后的值?
// 正则匹配连续的空白字符作为分隔符分割
List<String> wordList = Arrays.asList(s.split("\\s+"));
Collections.reverse(wordList);
return String.join(" ", wordList);
}
}
// leecode官方解法2 自己编写对应函数
class Solution {
public String reverseWords(String s) {
StringBuilder sb = trimSpaces(s);
// 翻转字符串
reverse(sb, 0, sb.length() - 1);
// 翻转每个单词
reverseEachWord(sb);
return sb.toString();
}
public StringBuilder trimSpaces(String s) {
int left = 0, right = s.length() - 1;
// 去掉字符串开头的空白字符
while (left <= right && s.charAt(left) == ' ') {
++left;
}
// 去掉字符串末尾的空白字符
while (left <= right && s.charAt(right) == ' ') {
--right;
}
// 将字符串间多余的空白字符去除
StringBuilder sb = new StringBuilder();
while (left <= right) {
char c = s.charAt(left);
if (c != ' ') {
sb.append(c);
} else if (sb.charAt(sb.length() - 1) != ' ') {
sb.append(c);
}
++left;
}
return sb;
}
public void reverse(StringBuilder sb, int left, int right) {
while (left < right) {
char tmp = sb.charAt(left);
sb.setCharAt(left++, sb.charAt(right));
sb.setCharAt(right--, tmp);
}
}
public void reverseEachWord(StringBuilder sb) {
int n = sb.length();
int start = 0, end = 0;
while (start < n) {
// 循环至单词的末尾
while (end < n && sb.charAt(end) != ' ') {
++end;
}
// 翻转单词
reverse(sb, start, end - 1);
// 更新start,去找下一个单词
start = end + 1;
++end;
}
}
}
String.join(" “, wordList); // 将list内容连接成字符串。第一个参数是分隔符。第二个参数是待连接的素材。源码中使用的是stringBuilder。
Arrays.asList(); // 该方法是将数组转化成List集合的方法
Collections.reverse(); // 反转list集合内容
s.split(”\s+"); // “\s+”中的+表示一个或多个的意思
卡码网:55.右旋转字符串
建议:题解中的解法如果没接触过的话,应该会想不到
题目链接/文章讲解:55.右旋转字符串
JZ58 左旋转字符串
需要额外申请一个StringBuilder空间
public class Solution {
public String RightRotateString (String str, int n) {
//取余,因为每次长度为n的旋转数组相当于没有变化
if(str.isEmpty() || str.length == 0){
return "";
}
//取余,因为每次长度为m的旋转数组相当于没有变化
int mod = n % str.length();
StringBuilder res = new StringBuilder();
for(int i = str.length - mod; i < str.length; i++) res.append(str.charAt(i));
for(int i = 0; i < mod; i++) res.append(str.charAt(i));
return res.toSting();
}
}
类似上1题,先整体反转,再局部反转
思路就是 通过 整体倒叙,把两段子串顺序颠倒,两个段子串里的的字符在倒叙一把,负负得正,这样就不影响子串里面字符的顺序了
但是对于java来说还是需要一个额外数组空间
// 方法3 代码随想录
public class Solution {
public String LeftRotateString (String str, int n) {
//取余,因为每次长度为n的旋转数组相当于没有变化
if(str.isEmpty() || str.length() == 0)
return "";
int m = str.length();
//取余,因为每次长度为m的旋转数组相当于没有变化
n = n % m;
char[] chars = str.toCharArray();
reverseString(chars, 0, str.length() - 1);
reverseString(chars, 0, str.length() - n - 1);
reverseString(chars, str.length() - n, str.length() - 1);
return new String(chars);
}
public static void reverseString(char[] ch, int start, int end) {
//异或法反转字符串,参照题目 344.反转字符串的解释
while (start < end) {
ch[start] ^= ch[end];
ch[end] ^= ch[start];
ch[start] ^= ch[end];
start++;
end--;
}
}
}
###遇到的不熟悉的基础语法
res.toSting(); // StringBuilder类型转换为字符串
char[] chars = str.toCharArray(); // 字符串转换为一个字符数组
new String(chars); // 字符数组转换为字符串
//异或法反转字符串,参照题目 344.反转字符串的解释
while (start < end) {
ch[start] ^= ch[end];
ch[end] ^= ch[start];
ch[start] ^= ch[end];
start++;
end–;
}