题目描述
给你一个字符串 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 <= 10^4
s
包含英文大小写字母、数字和空格' '
s
中 至少存在一个 单词
进阶:如果字符串在你使用的编程语言中是一种可变数据类型,请尝试使用 O(1)
额外空间复杂度的 原地 解法。
思路
本题的主要解题思路可以分为三步:
- 移除字符串首部、中间、尾部的多余空格。
- 将整个字符串反转。
- 将字符串的每个单词反转。
在第1步笔者使用的是快慢指针法,让快指针去寻找新字符串的字符,慢指针则记录新字符串的最后一个字符。中间空格的处理比较麻烦,需要保留一个空格,此时当遇到空格+空格的情况时,让fast++,否则交换s[slow]和s[fast],那么当遇到字符+空格的情况时,那个空格便会被保留下来,从而实现删除中间多余的空格。不过最后一个单词后面的空格也会被保留下来,在去除尾部空格的时候需要注意。
Python有好用的函数可以直接去除空格和切割单词,将单词分割开后再反转,最后拼接即可。
代码
C++版:
class Solution {
public:
string reverseWords(string s) {
// 在C++中string可被修改,因此考虑使用O(1)额外空间的解法
// 1.去除多余空格,使用快慢指针法
// 2.反转整个字符串
// 3.反转字符串中的每个单词
int slow=0;
int fast=0;
// 将fast移动到第一个非空格元素
while(fast<s.size() && s[fast]==' '){
fast++;
}
// 快指针负责寻找新数组的元素
// 去除首部和中间的空格
while(fast<s.size()){
// 对于中间的空格,只有是连续的2个空格以上的情况时,fast才会跳过
if(fast-1>=0 && s[fast]==' ' && s[fast-1]==' '){
fast++;
}
else{
// 连续的空格段中,第一个空格会被加入到新字符串中
// 注意会导致新字符串的最后一位必然是空格
s[slow++]=s[fast++];
}
}
// 去除末尾的空格
if(slow-1>=0 && s[slow-1]==' '){
s.resize(slow-1);
}else{
s.resize(slow);
}
// 反转整个字符串
reverse(s.begin(),s.end());
// 反转每个单词
int start=0; // 记录单词开始位置
for(int i=0;i<=s.size();i++){
if(i==s.size() || s[i]==' ' ){
reverse(s.begin()+start,s.begin()+i);
start=i+1;
}
}
return s;
}
};
Python版:
class Solution:
def reverseWords(self, s: str) -> str:
# 去除多余空格,将字符串拆分为单词,即转换成列表类型
words = s.split()
# 反转单词
left, right = 0, len(words) - 1
while left < right:
words[left], words[right] = words[right], words[left]
left += 1
right -= 1
# 将列表转换成字符串
return " ".join(words)
需要注意的地方
1.str.reverse(str.begin(),str.end())中str.end()指的是字符串str最后一个字符的下一个位置。
2.erase()操作的时间复杂度是O(n)。
3.Python和Java都不能在字符串上修改,需要申请新空间,而C++可以在字符串上修改,因此能用O(1)的空间完成本题。