0%

151.反转字符串中的单词

倒序遍历

题目要求反转单词顺序,同时去掉多余空格,因此可以直接从后往前遍历字符串,每次提取一个完整单词加入答案。

做法是从字符串末尾开始,先跳过空格,再找到当前单词的左右边界,将该单词加入结果。之后继续向前重复这一过程。由于是按从后往前提取,所以最终拼接出的字符串天然就是单词逆序,同时只在单词之间手动加一个空格即可避免多余空格。

时间复杂度 $O(n)$

空间复杂度 $O(n)$

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class Solution {
public String reverseWords(String s) {
StringBuilder sb = new StringBuilder();
int end = s.length() - 1;
for (;;) {
int[] cur = getWord(s, end);
end = cur[0] - 1;
if (cur[0] == -1) {
break;
}
sb.append(s, cur[0], cur[1]);
sb.append(' ');
}
if (sb.length() > 0) {
sb.setLength(sb.length() - 1);
}
return sb.toString();
}

private int[] getWord(String s, int i) {
int[] ans = new int[]{-1, -1};
while (i >= 0 && s.charAt(i) == ' ') {
i--;
}
if (i >= 0) {
ans[1] = i + 1;
while (i >= 0 && s.charAt(i) != ' ') {
i--;
}
ans[0] = i + 1;
}
return ans;
}
}

双指针

也可以先去掉首尾空格,然后用双指针在字符串中从右往左扫描。

设 $r$ 和 $l$ 都指向当前待处理单词的末尾,先让 $l$ 左移找到这个单词的起点,再把这一段加入答案。随后继续跳过前面的空格,并更新下一轮单词的右边界。这样同样能够按逆序提取所有单词。

这种写法更紧凑,本质上仍然是从后往前逐个找单词。

时间复杂度 $O(n)$

空间复杂度 $O(n)$

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution {
public String reverseWords(String s) {
s = s.trim();
int r = s.length() - 1, l = r;
StringBuilder ans = new StringBuilder();
while (l >= 0) {
while (l >= 0 && s.charAt(l) != ' ') {
l--;
}
ans.append(s, l + 1, r + 1).append(' ');
while (l >= 0 && s.charAt(l) == ' ') {
l--;
}
r = l;
}
return ans.toString().trim();
}
}