java中的字符串
- **String不能修改!!**要修改只能用StringBuilder!
sb.apppend();
- 字符串相关方法
字符串长度是str.length()
str.charAt()
构造方法传char数组:new String(chars)
344.反转字符串
题目链接:https://leetcode.cn/problems/reverse-string/
视频链接:https://www.bilibili.com/video/BV1fV4y17748/?spm_id_from=333.788&vd_source=80cf8293f27c076730af6c32ceeb2689
讲解链接:https://programmercarl.com/0344.%E5%8F%8D%E8%BD%AC%E5%AD%97%E7%AC%A6%E4%B8%B2.html
双指针
也是用双指针,一个从头,一个从尾,在中间汇合。每交换一次i++,j–。
while(i < j)
当i=j时不需要交换了,因此不写等号。
swap方法实现
swap可以有两种实现。
- 一种就是常见的交换数值:
int tmp = s[i];
s[i] = s[j];
s[j] = tmp;
- 一种就是通过位运算:
s[i] ^= s[j];
s[j] ^= s[i];
s[i] ^= s[j];
class Solution {
public void reverseString(char[] s) {
int i = 0;
int j = s.length-1;
while(i < j) {
char tmp = s[i];
s[i] = s[j];
s[j] = tmp;
i++;
j--;
}
}
}
541.反转字符串II
题目链接:https://leetcode.cn/problems/reverse-string-ii/description/
视频链接:https://www.bilibili.com/video/BV1dT411j7NN/?spm_id_from=333.788&vd_source=80cf8293f27c076730af6c32ceeb2689
讲解链接:https://programmercarl.com/0541.%E5%8F%8D%E8%BD%AC%E5%AD%97%E7%AC%A6%E4%B8%B2II.html#%E7%AE%97%E6%B3%95%E5%85%AC%E5%BC%80%E8%AF%BE
思路
修改循环遍历,不要用i++,这里改成每次步进2k个。
for(int i = 0;i < len; i += 2*k)
注意reverse函数里是左闭右闭的!
class Solution {
public void reverse(char[] s, int i, int j) {
while(i < j) {
char tmp = s[i];
s[i] = s[j];
s[j] = tmp;
i++;
j--;
}
}
public String reverseStr(String s, int k) {
char[] chars = s.toCharArray();
int cnt = 0;
int len = chars.length;
for(int i = 0; i < len; i+=2*k) { //每次步进2k,翻转前k个
int rem = len - i;
if(rem < k) {
reverse(chars, i ,len-1);
break;
}
if(rem >= k && rem < 2*k) {
reverse(chars,i,i+k-1);
break;
}
reverse(chars,i,i+k-1);
}
String result = new String(chars);
return result;
}
}
卡码网54.替换数字
c++的做法是扩容数组,为替换成number预留出空间,然后从后向前覆盖。
java因为String不能变,只能另外开一个sb,遍历s的同时,动态append到sb后面。
是数字就append("number")
,不是就append(s.charAt(i))
。
判定是不是数字用Character.isDigit()
class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String s = sc.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);
}
}
151.反转字符串中的单词
思路
要求:空间O(1),不用库函数
不仅要去除首尾的空格,还要去除重复的空格。
整体思路:先整体反转,再反转每一个单词
-
先将整体字符串反转了。eg:
he__wo
(_代表空格) -
反转后变成:
ow__eh
,单词内部没转过来,再针对每一个单词做反转。 -
最后变成:
wo__he
,就是结果了!!!
- 总体逻辑
public String reverseWords(String s) {
char[] c = s.toCharArray();
c = deleteExtraSpaces(c);
//先整体反转一下
reverse(c,0,c.length-1);
//然后反转每个单词:
reverseEachWord(c);
return new String(c);
}
- 怎么删除多余的空格?
回忆数组中的移除元素那题,这里我们移除的就是空格元素。这里是在原地操作!!
定义快慢指针,快指针用来指向符合的字符,慢指针用来指向快指针更新的字符应该更新在哪里。
特殊处理首个单词不留空格,if(slow!=0) s[slow++]=' '
public char[] deleteExtraSpaces(char[] s) {
//快慢指针移除首尾和多余的空格
int slow = 0; //慢指针负责指定符合的元素要放的位置
for(int i = 0; i < s.length; i++) {
if(s[i] != ' ') { //遇到不为空格的才处理 为空格就跳过
if(slow != 0) { //如果第一个字符是单词,就不手动加空格了
//进到这里说明:1.s[slow]不是空格 2.不是第一个单词。要手动加一个空格
s[slow++] = ' ';
}
while(i < s.length && s[i]!=' '){ //在while里把快指针找到的单词一个个移动过来
s[slow++] = s[i++];
}
}
}
//后面的相当于cpp里的resize,重新开一个空间合适的新数组
char[] newChars = new char[slow];
System.arraycopy(s, 0, newChars, 0, slow);
return newChars;
}
- 单个单词反转的方法逻辑
public void reverseEachWord(char[] c) {
int start = 0; //存储每个单词的开始位置
for(int i = 0; i <= c.length; i++){
if(i == c.length || c[i] == ' ') { //如果i到了末尾或者到了空格,就说明找到了一整个单词[start,i-1]
reverse(c,start,i-1);
start = i+1;//更新start,指向下一个单词的开始位置
}
}
}
注意判断是否到了末尾或空格那里,用||连接,而且要先判断i==c.length,否则会越界!!
reverse传参是左闭右开,进到if了就说明此时i指向空格或者末尾(下标是length)
- java代码
class Solution {
//反转,左闭右闭
public void reverse(char[] s, int i, int j) {
while(i < j) {
char tmp = s[i];
s[i] = s[j];
s[j] = tmp;
i++;
j--;
}
}
public char[] deleteExtraSpaces(char[] s) {
//快慢指针移除首尾和多余的空格
int slow = 0; //慢指针负责指定符合的元素要放的位置
for(int i = 0; i < s.length; i++) {
if(s[i] != ' ') { //遇到不为空格的才处理 为空格就跳过
if(slow != 0) { //如果要放的位置是第一个,就不手动加空格了
//进到这里说明:1.s[slow]不是空格 2.不是第一个单词。要手动加一个空格
s[slow++] = ' ';
}
while(i < s.length && s[i]!=' '){ //在while里把快指针找到的单词一个个移动过来
s[slow++] = s[i++];
}
}
}
char[] newChars = new char[slow];
System.arraycopy(s, 0, newChars, 0, slow);
return newChars;
}
public void reverseEachWord(char[] c) {
int start = 0; //存储每个单词的开始位置
for(int i = 0; i <= c.length; i++){
if(i == c.length || c[i] == ' ') { //如果i到了末尾或者到了空格,就说明找到了一整个单词[start,i-1]
reverse(c,start,i-1);
start = i+1;//更新start,指向下一个单词的开始位置
}
}
}
public String reverseWords(String s) {
char[] c = s.toCharArray();
c = deleteExtraSpaces(c);
//先整体反转一下
reverse(c,0,c.length-1);
//然后反转每个单词:
reverseEachWord(c);
return new String(c);
}
}
卡码网55.右旋字符串
题目链接:https://kamacoder.com/problempage.php?pid=1065
讲解链接:https://programmercarl.com/kama55.%E5%8F%B3%E6%97%8B%E5%AD%97%E7%AC%A6%E4%B8%B2.html#%E6%80%9D%E8%B7%AF
负负得正,先反转前一段[0,k-1]子串 在反转后一段[k,len-1]。
最后反转整个串[0,len-1]
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = Integer.parseInt(in.nextLine());
String s = in.nextLine();
int len = s.length(); //获取字符串长度
char[] chars = s.toCharArray();
reverseString(chars, 0, len - 1); //反转整个字符串
reverseString(chars, 0, n - 1); //反转前一段字符串,此时的字符串首尾尾是0,n - 1
reverseString(chars, n, len - 1); //反转后一段字符串,此时的字符串首尾尾是n,len - 1
System.out.println(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--;
}
}
}
day8总结
- java中String是不可变的。可以考虑新建一个
StringBuilder
然后用append
拼接,或者用toCharArray
方法转化成char数组再进行操作。最后返回的时候return new String(chars)
。 - 左旋/右旋字符串:先整体反转,再分别反转左半部分和右半部分即可
- swap方法可以用tmp或者位运算实现。注意是左闭右闭的
- 去除一个字符串中多余空格的逻辑比较复杂,回顾
移除数组
那道题里的实现,用快慢指针,slow指向符合的元素要放的位置,fast指针遍历整个串 去找不为空格的字符。放完一个单词之后要手动添加一个空格(注意首个字符的情况 不用放) - 已经去掉多余空格之后,寻找单个的单词也是用双指针,start记录一个单词的起始位置,i去找结束位置,一旦为空格就停下,此时
reverse(start,i-1)
.然后start更新成i+1
!