0557-反转字符串中的单词 III

Raphael Liu Lv10

给定一个字符串 s ,你需要反转字符串中每个单词的字符顺序,同时仍保留空格和单词的初始顺序。

示例 1:

**输入:** s = "Let's take LeetCode contest"
**输出:** "s'teL ekat edoCteeL tsetnoc"

示例 2:

**输入:** s = "God Ding"
**输出:** "doG gniD"

提示:

  • 1 <= s.length <= 5 * 104
  • s 包含可打印的 ASCII 字符。
  • s 不包含任何开头或结尾空格。
  • s至少 有一个词。
  • s 中的所有单词都用一个空格隔开。

方法一:使用额外空间

思路与算法

开辟一个新字符串。然后从头到尾遍历原字符串,直到找到空格为止,此时找到了一个单词,并能得到单词的起止位置。随后,根据单词的起止位置,可以将该单词逆序放到新字符串当中。如此循环多次,直到遍历完原字符串,就能得到翻转后的结果。

代码

[sol1-C++]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Solution {
public:
string reverseWords(string s) {
string ret;
int length = s.length();
int i = 0;
while (i < length) {
int start = i;
while (i < length && s[i] != ' ') {
i++;
}
for (int p = start; p < i; p++) {
ret.push_back(s[start + i - 1 - p]);
}
while (i < length && s[i] == ' ') {
i++;
ret.push_back(' ');
}
}
return ret;
}
};
[sol1-Java]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Solution {
public String reverseWords(String s) {
StringBuffer ret = new StringBuffer();
int length = s.length();
int i = 0;
while (i < length) {
int start = i;
while (i < length && s.charAt(i) != ' ') {
i++;
}
for (int p = start; p < i; p++) {
ret.append(s.charAt(start + i - 1 - p));
}
while (i < length && s.charAt(i) == ' ') {
i++;
ret.append(' ');
}
}
return ret.toString();
}
}
[sol1-JavaScript]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var reverseWords = function(s) {
const ret = [];
const length = s.length;
let i = 0;
while (i < length) {
let start = i;
while (i < length && s.charAt(i) != ' ') {
i++;
}
for (let p = start; p < i; p++) {
ret.push(s.charAt(start + i - 1 - p));
}
while (i < length && s.charAt(i) == ' ') {
i++;
ret.push(' ');
}
}
return ret.join('');
};
[sol1-C]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
char* reverseWords(char* s) {
int length = strlen(s);
char* ret = (char*)malloc(sizeof(char) * (length + 1));
ret[length] = 0;
int i = 0;
while (i < length) {
int start = i;
while (i < length && s[i] != ' ') {
i++;
}
for (int p = start; p < i; p++) {
ret[p] = s[start + i - 1 - p];
}
while (i < length && s[i] == ' ') {
ret[i] = ' ';
i++;
}
}
return ret;
}
[sol1-Golang]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
func reverseWords(s string) string {
length := len(s)
ret := []byte{}
for i := 0; i < length; {
start := i
for i < length && s[i] != ' ' {
i++
}
for p := start; p < i; p++ {
ret = append(ret, s[start + i - 1 - p])
}
for i < length && s[i] == ' ' {
i++
ret = append(ret, ' ')
}
}
return string(ret)
}

复杂度分析

  • 时间复杂度:O(N),其中 N 为字符串的长度。原字符串中的每个字符都会在 O(1) 的时间内放入新字符串中。

  • 空间复杂度:O(N)。我们开辟了与原字符串等大的空间。

方法二:原地解法

思路与算法

此题也可以直接在原字符串上进行操作,避免额外的空间开销。当找到一个单词的时候,我们交换字符串第一个字符与倒数第一个字符,随后交换第二个字符与倒数第二个字符……如此反复,就可以在原空间上翻转单词。

需要注意的是,原地解法在某些语言(比如 Java,JavaScript)中不适用,因为在这些语言中 String 类型是一个不可变的类型。

代码

[sol2-C++]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Solution {
public:
string reverseWords(string s) {
int length = s.length();
int i = 0;
while (i < length) {
int start = i;
while (i < length && s[i] != ' ') {
i++;
}

int left = start, right = i - 1;
while (left < right) {
swap(s[left], s[right]);
left++;
right--;
}
while (i < length && s[i] == ' ') {
i++;
}
}
return s;
}
};
[sol2-C]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
char* reverseWords(char* s) {
int length = strlen(s);
int i = 0;
while (i < length) {
int start = i;
while (i < length && s[i] != ' ') {
i++;
}

int left = start, right = i - 1;
while (left < right) {
char tmp = s[left];
s[left] = s[right], s[right] = tmp;
left++;
right--;
}
while (i < length && s[i] == ' ') {
i++;
}
}
return s;
}

复杂度分析

  • 时间复杂度:O(N)。字符串中的每个字符要么在 O(1) 的时间内被交换到相应的位置,要么因为是空格而保持不动。

  • 空间复杂度:O(1)。因为不需要开辟额外的数组。

 Comments
On this page
0557-反转字符串中的单词 III