给你一个字符串 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 <= 104
s
包含英文大小写字母、数字和空格' '
s
中 至少存在一个 单词
**进阶:**如果字符串在你使用的编程语言中是一种可变数据类型,请尝试使用 O(1)
额外空间复杂度的 原地 解法
class Solution {
public:
void reverse(string &s, int start,int end)
{
for(int i = start,j = end;i<j;i++,j--)
{
swap(s[i],s[j]);
}
}
void removeExtraSpaces(string& s){
int slow = 0;
for(int i = 0;i<s.size();++i){
if(s[i]!=' '){
if(slow !=0) s[slow++] = ' ';//在单词之间加一个空格
while(i<s.size()&&s[i]!=' '){
s[slow++] = s[i++];
}
}
}
s.resize(slow);//slow的大小即为去除多余空格之后的效果
}
string reverseWords(string s) {
removeExtraSpaces(s);
reverse(s,0,s.size()-1);
int start = 0;
for(int i = 0;i<=s.size();i++){
if(i==s.size()||s[i] == ' '){
reverse(s,start,i-1);
start = i + 1;
}
}
return s;
}
};
reverse
函数就不用多说,反转数组中的元素用
removeExtraSpaces
函数是为了去除字符串中多余的空格例如字符串前的空格,字符串后的空格,或者单词之间不止一个的空格。
使用双指针的思路,使用一个慢指针和一个快指针,慢指针指向新的位置,快指针是为了挑选原字符串的元素,也就是说快指针i需要遍历所有字符,挑选出需要的字符,放到慢指针所指向的位置
if(s[i]!=' ')
是为了所有字符串前面的空格,当第一次遇到不是空格的字符的时候,判断是否是第一个单词,如果不是意味着是后续的单词,就需要加一个空格,实现每个单词之间都有一个空格,while(i<s.size()&&s[i]!=' ')
的目的是将不是空格的元素,也就是单词通过慢指针重新赋予新的位置,例如遇到第一个单词的时候,由于slow=0所以不需要添加空格,至于第一个单词之前的空格已经在最外面的if(s[i]!=' ')
不满足条件于是跳过了,遇到的第一个单词的字符时会一个个把对应的i处的字符赋值到slow处,这样就完成了第一个单词的移动,当遇到第二个单词的时候,slow就不再=0,所以就需要添加一个空格,然后slow向后移动一个位置,继续完成后续元素的移动,最后字符串的长度就是slow的值.
reverseWords
函数就是具体实现反转单词的功能
第一步先调用
removeExtraSpaces(s)
移除多i与的空格,然后使用reverse(s,0,s.size()-1)对所有元素进行反转,最后再反转一个一个的单词,start是每个单词的初始位置,遍历每个元素,遇到空格意味着空格前面是上一个单词的最后一个字符,使用reverse(s,start,i-1)
处理完之后,将start=i+1,也就是空格的下一个元素,空格的下一个元素就是下一个单词的第一个元素,重复操作,直到反转所有单词,就完成了字符串中单词的反转。