题目描述:
给定一个字符串,逐个翻转字符串中的每个单词。
示例:
输入: "the sky is blue
",
输出: "blue is sky the
".
说明:
- 无空格字符构成一个单词。
- 输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。
- 如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个。
进阶: 请选用C语言的用户尝试使用 O(1) 空间复杂度的原地解法。
要完成的函数:
void reverseWords(string &s)
说明:
1、这道题给定一个字符串s,相当于一个英文句子,要求把这个句子中的单词反转一下,后面的要放在前面,前面放在后面。
这个句子中可能会有多余的空格,可能会出现在第一个字符前面,可能出现在单词之间,可能出现在最后一个字符后面。
你要将多余的空格去掉,最前面和最后面不能有空格,单词之间的空格只能有一个。
c或c++语言用户使用O(1)空间复杂度的原地解法,在字符串中修改,函数类型是void,不用返回。
2、这道题如果允许多定义一个新字符串(长度与给定字符串相同),那么从给定字符串的后面读起,读出的字符从新的字符串的前面开始写起。
在写的过程中,调整新字符串的空格,使之符合要求,最后调用resize函数修改新字符串的长度,这道题也就解决了。
但现在要求原地解法,那么只能逐个交换了,后面跟前面交换,这样子换完之后,单词内部顺序也是反过来的,那再在单词内部交换一下,也就ok了。
至于多余的空格问题,可以在交换之前,先解决掉这个问题,把后面的字符往前面移。
笔者的代码思路如下,举个例子,字符串是 "(两个空格)the(三个空格)sky(两个空格)is(一个空格)blue(两个空格)":
1、先反转整个字符串,变成(两个空格)eulb(一个空格)si(两个空格)yks(三个空格)eht(两个空格)。
2、把后面的字符往前挪,去掉多余的空格,变成eulb(一个空格)si(一个空格)yks(一个空格)eht
3、在单词内部进行反转,变成blue(一个空格)is(一个空格)sky(一个空格)the。
所以具体代码如下:(附详解)
void reverseWords(string &s)
{
reverse(s.begin(),s.end());//先进行整个字符串的反转
int i=0,j=0,start=0,t;
while(i<s.size())//把字符往前挪,去掉多余的空格
{
while(i<s.size())//找到第一个非空格字符
{
if(s[i]!=' ')
break;
i++;
}
if(i==s.size())break;//如果找不到非空格字符,此时已经i==s.size(),所以直接结束这一部分的任务
j=i+1;
while(j<=s.size())//找到i后面的第一个空格字符,位置记为j
{
if(s[j]==' '||s[j]==' ')
break;
j++;
}
while(i<j)//把i和j之间的字符往前挪,第一个就搬动到start这个位置,第二个搬动到start+1这个位置……
{
s[start]=s[i];
start++;
i++;
}
s[start]=' ';//搬完一个单词之后,start现在这个位置变成空格字符
start++;//start到空格的下一位,作为新的单词的起点
i++;//i退出循环时,i==j,现在i++,变成空格的下一位,继续找下一个单词的起点
}
if(start==0)//边界条件,如果结束了上述任务之后,start还是为0,说明根本就没有非空格字符,那么s变成空字符串
s=s.substr(0,0);
else
{
s=s.substr(0,start-1);//去掉字符串后面多余的长度
i=0,j=1;
while(i<s.size())//把每一个单词反转过来
{
while(j<=s.size())//找到空格位置,记为j
{
if(s[j]==' '||s[j]==' ')
break;
j++;
}
t=j+1;//记下来,作为下一个单词的起始位置
j--;
while(i<j)//单词内部反转
{
swap(s[i],s[j]);
i++;
j--;
}
i=t,j=i+1;//更新i和j的位置
}
}
上述代码实测4ms,beats 98.93% of cpp submissions。