问题
给定一个字符串,逐个翻转字符串中的每个单词
说明:
- 无空格字符构成一个单词
- 输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括
如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个
示例 1:
输入:”the sky is blue”
输出:”blue is sky the”
示例 2:
输入:” hello world! “
输出:”world! hello”
解释:输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括
示例 3:
输入:”a good example”
输出:”example good a”
解释:如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个
示例 4:
输入:s = “ Bob Loves Alice “
输出:”Alice Loves Bob”
示例 5:
输入:s = “Alice does not even like bob”
输出:”bob like even not does Alice”
方法一:Java语言特性
class Solution {
public String reverseWords(String s) {
// trim() 方法用于删除字符串的头尾空白符
s = s.trim();
// 正则匹配连续的空白字符作为分隔符分割
// List<String>不能直接实例化
/**split("\\s+")按空格、制表符等进行拆分(也就是说它是按空白部分进行拆分,不管这个空白使用什么 操作留下的,提如空格键 tab键)
split(" +") 按空格进行拆分(也就是说只有按空格键流出来的空白才会是拆分的一句)
\\s表示 空格,回车,换行等空白符,+号表示一个或多个的意思
*/
List<String> wordList = Arrays.asList(s.split("\\s+")); // 将数组转化成list集合
/**
sd@sdd@sddd
split("@")
[sd,sdd,sddd]
*/
Collections.reverse(wordList);
return String.join(" ", wordList);
}
}
时间复杂度:
,其中 N 为输入字符串的长度
空间复杂度:
,用来存储字符串分割之后的结果
方法二
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);
//setCharAt(int index,Char ch),第一个参数是取代的位置索引从0开始,第二个参数是你要替换 为的字符串
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;
}
}
}
时间复杂度:
,其中 N 为输入字符串的长度
空间复杂度:
,N 为存储字符串的长度
方法三:双端队列
由于双端队列支持从队列头部插入的方法,因此我们可以沿着字符串一个一个单词处理,然后将单词压入队列的头部,再将队列转成字符串即可
class Solution {
public String reverseWords(String s) {
int left = 0, right = s.length() - 1;
// 去掉字符串开头的空白字符
while (left <= right && s.charAt(left) == ' ') {
++left;
}
// 去掉字符串末尾的空白字符
while (left <= right && s.charAt(right) == ' ') {
--right;
}
Deque<String> d = new ArrayDeque<String>();
StringBuilder word = new StringBuilder();
while (left <= right) {
char c = s.charAt(left);
if ((word.length() != 0) && (c == ' ')) {
// 将单词 push 到队列的头部
d.offerFirst(word.toString());
word.setLength(0);
} else if (c != ' ') {
word.append(c);
}
++left;
}
d.offerFirst(word.toString());
return String.join(" ", d);
}
}