力扣151:翻转字符串里的单词
题目描述:
给定一个字符串,逐个翻转字符串中的每个单词。
说明:
无空格字符构成一个 单词 。
输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。
如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个。
示例 1:
输入:“the sky is blue”
输出:“blue is sky the”
示例 4:
输入:s = " Bob Loves Alice "
输出:“Alice Loves Bob”
这道题目用了四种不同的解法,每种解法都有自己的独到之处。
解法一
解释
//方法一
class Solution {
public String reverseWords(String s) {
s = s.trim();
StringBuilder sb = new StringBuilder();
char[] charArray = s.toCharArray();
int len = charArray.length;
//获取一个单词word
for(int i = len-1;i >= 0;){
StringBuilder word = new StringBuilder("");//初始化为空字符串便于统计下一个单词
//处理到第一个字符时,不再减了,否则越界;试了单独判断当i=-1时即break;最后想到直接把两个条件顺序变了就可以了,因为先判断i>=0,若不符合=-1时,便不再判断后面的为空条件(与的特性),就完美解决了问题while(charArray[i] != ' ' && i>=0),这样就不行,到第一个字符时会数组越界
while(i >= 0 && charArray[i] != ' '){
word.append(charArray[i]);
i--;
}
word.reverse();//得到单词的反序,将其反转得到单词
sb.append(word);//将该单词添加到sb中
//最后一个单词结束时不应该有空格
if(i != -1)
sb.append(' ');
//碰到空格了(可能是多个空格),则利用循环,碰到空格时不管遍历下一个
while(i > 0 && charArray[i] == ' '){
i--;
}
}
return sb.toString();
}
}
//时间:80%O(N);空间:O(N)30%
解法二:
class Solution{
public String reverseWords(String s) {
s = s.trim();//去掉首尾端空格
//先用支持正则化的split将含有多个空格的字符串分割成字符串数组,因为字符串数组没有反转功能,再将字符串数组转成字符串列表
List<String> wordList = Arrays.asList(s.split("\\s+"));
//反转列表,Collections类中很多都是静态方法,所以类直接调用。Collections.reverse(list)
Collections.reverse(wordList);
//将反转后列表中的单词拼接起来,用join,用法?
//用String方法中新增的方法join(String link, String[] arr),用连接符将字符串数组中的每个字符串连接起来
return String.join(" ", wordList);
}
}
//时间:22%,空间:28%
解法三:
/*方法三:
class Solution{
public String reverseWords(String s) {
s = s.trim();
String[] wordArray = s.split("\\s+");//也可以用substring截取每个单词
int len = wordArray.length;
StringBuilder sb = new StringBuilder();
for(int i = len - 1;i >= 0;i --){
sb.append(wordArray[i]);
if(i != 0){
sb.append(" ");
}
}
return sb.toString();
}
}
//时间:13%,空间:46%
解法四:
/*方法四:空间O(1) 时间:5%,空间:74%
class Solution{
public String reverseWords(String s) {
//先将整个字符串反转
s = s.trim();
int len = s.length();
//new StringBuilder(s).reverse();这样不对,因为s还是String类型,而且String是不可变的,那么O(1)怎么理解???
StringBuilder sb = new StringBuilder(s).reverse();
System.out.println(sb);
//将每个单词反转
for(int i = 0; i < sb.length();){
//找出一个单词
int start = i;
len = sb.length();
while(i < len && sb.charAt(i) != ' '){
i++;
}//i=len
System.out.println(i);
int end = i-1;
if(i < len){
int j = i + 1;//保留一个空格i处
//删除多个空格
while(i < len && sb.charAt(i) == ' '){
i++;
}
System.out.println(i + "===" + sb.charAt(i));
sb.delete(j,i);//左闭右开
i -= i - j; // 因为你删除了两个空格,字符串的长度随着改变,那么原来指向 d 的 i,不在指向 d
//反转单词
reverseWord(sb,start,end);
}
else{
reverseWord(sb,start,end);
}
}
return sb.toString();
}
public void reverseWord(StringBuilder sb, int start, int end){//左闭右闭
System.out.println(start + " " + end);
for(int i = start,j = end;i <= j;i++,j--){
char tmp = sb.charAt(i);//charAt(i)注意是圆括号,不是方括号
sb.setCharAt(i, sb.charAt(j));
sb.setCharAt(j, tmp);
}
}
}
解法五:
/*空间为O(1)的题解
class Solution {
public String reverseWords(String s) {
if(s==null || (s=s.trim()).isEmpty()) return "";
int i,j,start,end;
//首先翻转trim()后的一大长条字符串,之后再翻转每个单词(String内定义的char[]用final修饰,不可再变)
StringBuilder sentence=new StringBuilder(s).reverse();
//用来记录一个单词的前后两个空格
start=end=0;
for(i=0;i<sentence.length();i++){
//如果碰到了一个空格,说明这个空格前到之前的一个空格已经有一个单词了,现在要翻转这个单词了
if(sentence.charAt(i)==' '){
//单词之间只能有一个空格,删除多余空格
j=i+1;
while(sentence.charAt(j)==' '){
j++;
}
//delete方法前 包括,后 不包括
sentence.delete(i+1,j);
//翻转单个单词
end=i-1;
revSingleWord(sentence,start,end);
//重新确定下一个单词的起始位置
start=i+1;
}
}
//由于最后一个单词末尾没有空格,所以这里多处理一下
revSingleWord(sentence,start,i-1);
return sentence.toString();
}
//翻转单个单词
public void revSingleWord(StringBuilder sentence,int start,int end){
while(start<end){
char temp=sentence.charAt(start);
sentence.setCharAt(start++,sentence.charAt(end));
sentence.setCharAt(end--,temp);
}
}
}