leetcode 344.反转字符串、541. 反转字符串II、151.翻转字符串里的单词、卡码网:54.替换数字、卡码网:55.右旋转字符串
leecode 344.反转字符串
题目链接 :https://leetcode.cn/problems/reverse-string/
题目
编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 char[] 的形式给出。
不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。
你可以假设数组中的所有字符都是 ASCII 码表中的可打印字符。
示例 1:
输入:[“h”,“e”,“l”,“l”,“o”]
输出:[“o”,“l”,“l”,“e”,“h”]
示例 2:
输入:[“H”,“a”,“n”,“n”,“a”,“h”]
输出:[“h”,“a”,“n”,“n”,“a”,“H”]
解题思路
这道题就是双指针的应用了,其实这道题相对来说是比较简答的,之前做双指针的时候经常用到类似双指针相向而走的类型,具体实现代码为:
class Solution {
public void reverseString(char[] s) {
int start = 0; //左指针
int end = s.length - 1; //右指针
while(start <= end) { //相向而行,交换数据
char tmp = s[start];
s[start] = s[end];
s[end] = tmp;
start++;
end--;
}
}
}
知识点
双指针
注意事项
相关题目
- 反转字符串中的元音字母
leecode 541. 反转字符串II
题目链接 :https://leetcode.cn/problems/reverse-string-ii/description/
题目
给定一个字符串 s 和一个整数 k,从字符串开头算起, 每计数至 2k 个字符,就反转这 2k 个字符中的前 k 个字符。
如果剩余字符少于 k 个,则将剩余字符全部反转。
如果剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符,其余字符保持原样。
示例:
输入: s = “abcdefg”, k = 2
输出: “bacdfeg”
解题思路
这道题也是双指针的应用。要审题,i是每次走2k步,然后翻转的是前k个字符,那也就是说起码位置确定了,i走完2k步之后的位置确定了,要翻转的范围也就确定了。所以,要定义一个变量start在i每次走完2k步时,从start开始,翻转前k个字符,范围不就是start+k-1吗。当然,可能后面剩下的不到k个,所以我们要曲字符串长度和start+k-1的最小值。具体实现代码为:
class Solution {
public String reverseStr(String s, int k) {
char[] arr = s.toCharArray(); //转化字符数组,因为string类型不可变
for (int i = 0; i < arr.length; i += 2 * k) { //注意,i每次走2k步
int start = i; //记录起始位置
int end = Math.min(arr.length - 1,start + k - 1); //终点位置
while (start < end) { //翻转
char tmp = arr[start];
arr[start] = arr[end];
arr[end] = tmp;
start++;
end--;
}
}
return new String(arr); //返回修改之后的字符串
}
}
知识点
双指针
注意事项
i每次走的步数,以及怎么让确定翻转范围,以及后面字符个数不足k个怎么去处理
相关题目
- 反转字符串中的单词 III
leecode 151.翻转字符串里的单词
题目链接 :https://leetcode.cn/problems/reverse-words-in-a-string/description/
题目
给你一个字符串 s ,请你反转字符串中 单词 的顺序。
单词 是由非空格字符组成的字符串。s 中使用至少一个空格将字符串中的 单词 分隔开。
返回 单词 顺序颠倒且 单词 之间用单个空格连接的结果字符串。
注意:输入字符串 s中可能会存在前导空格、尾随空格或者单词间的多个空格。返回的结果字符串中,单词间应当仅用单个空格分隔,且不包含任何额外的空格。
示例 1:
输入: “the sky is blue”
输出: “blue is sky the”
示例 2:
输入: " hello world! "
输出: “world! hello”
解释: 输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。
示例 3:
输入: “a good example”
输出: “example good a”
解释: 如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个
示例 1:
输入:[“h”,“e”,“l”,“l”,“o”]
输出:[“o”,“l”,“l”,“e”,“h”]
示例 2:
输入:[“H”,“a”,“n”,“n”,“a”,“h”]
输出:[“h”,“a”,“n”,“n”,“a”,“H”]
解题思路
这道题是多种操作的结合,包括了字符串的去空格,翻转,字符串内部单词的翻转。这里我给出两种解法,但其实是一样的,就是看代码怎么写。第一种去空格是借助了库函数trim(),然后利用StringBuffer和双指针从后往左去记录字符串和去除单词间的空格。具体实现代码为:
class Solution {
public String reverseWords(String s) {
s = s.trim(); //去除空格
int j = s.length() - 1; //尾指针,从后往前遍历,因为要翻转
StringBuffer sb = new StringBuffer(); //因为string类型不可变,但是stringbuffer类型是可以变的
while (j >= 0) {
int end = j; //记录这个单词的翻反转起始位置
while (j >= 0 && s.charAt(j) != ' ') j--; //找到第一个空格,注意j>=0,不然会越界
int i = j + 1; //从空格的后一个位置开始,即范围是[j+1,end]
while (i <= end) {
sb.append(s.charAt(i));//从后往前记录
i++;
}
sb.append(' ');//插入单词间的空格
while (j >= 0 && s.charAt(j) == ' ') j--; //再找到下一次单词的要反转的起始位置,注意j>=0,不然会越界
}
return sb.toString().trim(); //这里也要进行去空格,因为上面代码往sb插入单词后,会再插入一个空格。所以这里也要去空格,这也是这个算法不是很高效的原因之一。
}
}
起始可以直接先去除首位空格和中间空格,然后对整个字符串反转,再对字符串的单词进行反转。具体实现代码为:
class Solution {
public String reverseWords(String s) {
StringBuffer sb = removerSpace(s); //去除首位及中间多余空格
reverseString(sb,0,sb.length() - 1);
reverseEachWord(sb);
return sb.toString();
}
// 去除首尾以及中间多余空格
public StringBuffer removerSpace(String s) {
int start = 0;
int end = s.length() - 1;
while (s.charAt(start) == ' ') start++; //跳过首部空格
while (s.charAt(end) == ' ') end--; //跳过尾部空格
StringBuffer sb = new StringBuffer();
while (start <= end) {
if (s.charAt(start) != ' ' || sb.charAt(sb.length() - 1) != ' ') { //这里去除中间多余空格
sb.append(s.charAt(start));
}
start++;
}
return sb;
}
//反转字符串指定区间[start, end]的字符
public void reverseString(StringBuffer sb,int start,int end) {
while (start < end) {
char tmp = sb.charAt(start);
sb.setCharAt(start,sb.charAt(end));
sb.setCharAt(end,tmp);
start++;
end--;
}
}
//反转各个单词
public void reverseEachWord(StringBuffer sb) {
int start = 0;
int end = 1;
int n = sb.length();
while (start < n) {
while (end < n && sb.charAt(end) != ' ') end++;
reverseString(sb,start,end - 1);
start = end + 1;
end = start + 1;
}
}
}
知识点
双指针
注意事项
怎么处理多余的空格以及又要保存一个空格在单词之间
相关题目
188 .反转字符串的单词II
卡码网:54.替换数字
题目链接 :https://kamacoder.com/problempage.php?pid=1064
题目
题目描述
给定一个字符串 s,它包含小写字母和数字字符,请编写一个函数,将字符串中的字母字符保持不变,而将每个数字字符替换为number。 例如,对于输入字符串 “a1b2c3”,函数应该将其转换为 “anumberbnumbercnumber”。
输入描述
输入一个字符串 s,s 仅包含小写字母和数字字符。
输出描述
打印一个新的字符串,其中每个数字字符都被替换为了number
输入示例
a1b2c3
输出示例
anumberbnumbercnumber
提示信息
数据范围:
1 <= s.length < 10000。
解题思路
这道题感觉是一道技巧题,遇到数字就在对应插入number。还是从后遍历,遇到数字,就插入按顺序反向插入number。但是要先确定长度,因为遇到一个数组就插入一个number,相当再插入5个位置。则新数组的长度应为输入字符串的长度*5。具体实现代码为:
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String s = sc.next();
int len = s.length();
for (int i = 0;i < s.length() ;i++ ) {
if (s.charAt(i) >= '0' && s.charAt(i) <= '9') {
len += 5; //记录新长度
}
}
char[] res = new char[len]; //构建新数组
for (int i = 0; i < s.length(); i++ ) {
res[i] = s.charAt(i); //先按顺序插入s的值,然后从新数组的最后面和s的最后面开始遍历
}
for (int i = s.length()-1,j = res.length - 1; i >= 0;i-- ) { //遇到数字,就反向插入number
if (res[i] >= '0' && res[i] <= '9') {
res[j--] = 'r';
res[j--] = 'e';
res[j--] = 'b';
res[j--] = 'm';
res[j--] = 'u';
res[j--] = 'n';
}else{
res[j--] = res[i];
}
}
System.out.println(res); //返回
}
}
知识点
双指针,字符串
注意事项
新的长度计算,怎么插入number
相关题目
卡码网:55.右旋转字符串
题目链接 :https://kamacoder.com/problempage.php?pid=1065
题目
题目描述
字符串的右旋转操作是把字符串尾部的若干个字符转移到字符串的前面。给定一个字符串 s 和一个正整数 k,请编写一个函数,将字符串中的后面 k 个字符移到字符串的前面,实现字符串的右旋转操作。
例如,对于输入字符串 “abcdefg” 和整数 2,函数应该将其转换为 “fgabcde”。
输入描述
输入共包含两行,第一行为一个正整数 k,代表右旋转的位数。第二行为字符串 s,代表需要旋转的字符串。
输出描述
输出共一行,为进行了右旋转操作后的字符串。
输入示例
2
abcdefg
输出示例
fgabcde
提示信息
数据范围:
1 <= k < 10000,
1 <= s.length < 10000;
解题思路
这道题仔细想想,不就是上面几道题类似的操作吗,起始就是将s.length()-n到s.leng()个字符插入到字符串前面,那我们先从后面开始遍历,然后再从第0为开始不就ok了吗。具体代码为:
import java.util.*;
public class Main{
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = Integer.parseInt(sc.nextLine());
String s = sc.nextLine();
int j = s.length() - n;
StringBuffer sb = new StringBuffer();
while(j < s.length()){
sb.append(s.charAt(j)); //从s.length()-n开始,将其插入到最前面
j++;
}
for (int i = 0; i < s.length() - n; i++) { //然后插入剩下的字符
sb.append(s.charAt(i));
}
System.out.println(sb.toString()); //返回
}
}
知识点
字符串
注意事项
怎么找到范围的下标开始位置和怎么插入