今天是字符串的加强训练,总共有5道题。实际上,通过今天的题目,我学会的,是StringBuilder的使用更加熟练,还有倒序反转有点肌肉记忆,其他的就是String的一些方法的比较熟练。
编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。
不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。
示例 1:
输入:s = ["h","e","l","l","o"]
输出:["o","l","l","e","h"]
示例 2:
输入:s = ["H","a","n","n","a","h"]
输出:["h","a","n","n","a","H"]
提示:
1 <= s.length <= 105
s[i] 都是 ASCII 码表中的可打印字符
这道题就是经典的双指针倒序,设定两个指针一个指向字符串头,一个指向字符串的末端,两两交换,直到最后两个指针相遇,退出循环。里面需要注意的是,String不能直接更改数值,因此需要先把它转换成字符类型的数组或者是转换成StringBuilder再进行操作,最后再转换回String形式return。
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 --;
}
}
}
给定一个字符串 s 和一个整数 k,从字符串开头算起,每计数至 2k 个字符,就反转这 2k 字符中的前 k 个字符。
如果剩余字符少于 k 个,则将剩余字符全部反转。
如果剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符,其余字符保持原样。
示例 1:
输入:s = "abcdefg", k = 2
输出:"bacdfeg"
示例 2:
输入:s = "abcd", k = 2
输出:"bacd"
提示:
1 <= s.length <= 104
s 仅由小写英文组成
1 <= k <= 104
这道题的关键在于怎么找到需要翻转的字符串的范围,翻转的代码上一题已经写过了。需要翻转的范围其实就是i+k-1个字符,为什么减1,因为第一个字符为0.i每次都增加2k长度。
class Solution {
public String reverseStr(String s, int k) {
int n = s.length();
char [] arr = s.toCharArray();
for(int i = 0; i < n; i += 2*k){
if(i + k <= n){
swap(i, i + k - 1, arr);
}else{
swap(i, n - 1, arr);
}
}
return new String(arr);
}
public void swap (int left, int right, char[] s){
while(left < right){
char temp;
temp = s[left];
s[left] = s[right];
s[right] = temp;
left ++;
right --;
}
}
}
请实现一个函数,把字符串 s 中的每个空格替换成"%20"。
示例 1:
输入:s = "We are happy."
输出:"We%20are%20happy."
限制:
0 <= s 的长度 <= 10000
这道题的思路很简单,是一个检索和装填的过程。遍历原来的字符串,遇到‘ ’的,就把它转变成%20装填到一个新数组或者是新的StringBuilder中,其他情况直接装填进去。其中主要在于StringBuilder的方法的熟练和调用。
class Solution {
public String replaceSpace(String s) {
StringBuilder sb = new StringBuilder();
for(int i = 0; i < s.length(); i ++){
if(s.charAt(i) == ' '){
sb.append("%20");
}else{
sb.append(s.charAt(i));
}
}
return sb.toString();
}
}
给你一个字符串 s ,请你反转字符串中 单词 的顺序。
单词 是由非空格字符组成的字符串。s 中使用至少一个空格将字符串中的 单词 分隔开。
返回 单词 顺序颠倒且 单词 之间用单个空格连接的结果字符串。
注意:输入字符串 s中可能会存在前导空格、尾随空格或者单词间的多个空格。返回的结果字符串中,单词间应当仅用单个空格分隔,且不包含任何额外的空格。
示例 1:
输入:s = "the sky is blue"
输出:"blue is sky the"
示例 2:
输入:s = " hello world "
输出:"world hello"
解释:反转后的字符串中不能存在前导空格和尾随空格。
示例 3:
输入:s = "a good example"
输出:"example good a"
解释:如果两个单词间有多余的空格,反转后的字符串需要将单词间的空格减少到仅有一个。
提示:
1 <= s.length <= 104
s 包含英文大小写字母、数字和空格 ' '
s 中 至少存在一个 单词
进阶:如果字符串在你使用的编程语言中是一种可变数据类型,请尝试使用 O(1) 额外空间复杂度的 原地 解法。
这道题可以切分成多个子目标来分别实现。首先是头尾的空格去除,接着是单词间多余空格的去除,再是单词的识别和反转。
需要注意的是中间空格的删除,做法是检测有没有连续两个空格,如果只有一个空格,表示正常的单词分隔,多个空格,就需要把多余的空格删除。
单词的反转整体思路为:(1)先把整个字符串翻转(2)识别出单词,再把每个单词进行翻转。比如源字符串为:"Hello World ",字符串反转:"dlroW olleH",再单词反转:"World Hello"
class Solution {
public String reverseWords(String s) {
StringBuilder sb = deleteSpace(s);
reversesString(sb);
reverseWords(sb);
return sb.toString();
}
public StringBuilder deleteSpace(String s){
StringBuilder sb = new StringBuilder();
int start = 0;
int end = s.length() - 1;
while(s.charAt(start) == ' '){
start ++;
}
while(s.charAt(end) == ' '){
end --;
}
while(start <= end){
if(s.charAt(start) != ' ' || s.charAt(start - 1) != ' '){
sb.append(s.charAt(start));
}
start ++;
}
return sb;
}
public void reversesString(StringBuilder sb){
int start = 0;
int end = sb.length() - 1;
while(start < end){
char temp = sb.charAt(start);
sb.setCharAt(start, sb.charAt(end));
sb.setCharAt(end, temp);
start ++;
end --;
}
}
public void reverseWords(StringBuilder sb){
int start = 0;
int end = start + 1;
sb.append(' ');
while(start < sb.length() - 1){
while(sb.charAt(end) != ' '){
end ++;
}
int left = start;
int right = end - 1;
while(left < right){
char temp = sb.charAt(left);
sb.setCharAt(left, sb.charAt(right));
sb.setCharAt(right, temp);
left ++;
right --;
}
start = end + 1;
end = start + 1;
}
sb.deleteCharAt(sb.length() - 1);
}
}
这里有一个需要注意的是翻转单词时,先在sb后面加一个空格,最后再删除。是为了给判断end等于‘ ’带来一致性的遍历,不然当end指向最后时有可能会出现指针越界问题。
字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。请定义一个函数实现字符串左旋转操作的功能。比如,输入字符串"abcdefg"和数字2,该函数将返回左旋转两位得到的结果"cdefgab"。
示例 1:
输入: s = "abcdefg", k = 2
输出: "cdefgab"
示例 2:
输入: s = "lrloseumgh", k = 6
输出: "umghlrlose"
限制:
1 <= k < s.length <= 10000
在完成前面几道题后,这道题就比较简单了。最容易的是直接拆分成两个String,在拼接就可以了。高一点的要求就是在一个字符串中完成,其实和上一题的翻转单词一个原理,只是识别号从‘ 空格’变成了特定长度而已。翻转过程:(1)整体翻转(2)两个小部分(单词)的翻转
class Solution {
public String reverseLeftWords(String s, int n) {
StringBuilder sb = new StringBuilder(s);
reverseString(sb, 0, s.length() - 1);
reverseString(sb, 0, s.length() - n - 1);
reverseString(sb, s.length() - n, s.length() - 1);
return sb.toString();
}
public void reverseString(StringBuilder sb, int left, int right){
int start = left;
int end = right;
while(start < end){
char temp = sb.charAt(start);
sb.setCharAt(start,sb.charAt(end));
sb.setCharAt(end,temp);
start ++;
end --;
}
}
}