题目:给你一个字符串 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”
解释:如果两个单词间有多余的空格,颠倒后的字符串需要将单词间的空格减少到仅有一个。
思路:
- 首先将字符串中多余的空格去掉。去掉空格分为三步。一是去掉前导空格,即字符串开头的空格;二是去掉中间多余的空格;三是去掉字符串结尾的空格。可以使用双指针解法,定义slow=0,fast=0。如果开头有空格,则fast一直右移,直到遇见不是空格的第一个字符。然后处理中间部分,如果当前位置是空格,并且前一个位置也是空格,fast指针继续右移,否则s[slow]=s[fast]。处理结尾的空格,如果结尾有空格,slow–。最后还需要重新定义一下字符串的大小。
- 将去掉多余空格的字符串进行反转。
- 对字符串里的每个单词再进行反转。定义两个指针,left=0和right=0。right右移,如果遇见空格,则对[left,right)区间内的字符进行反转,然后令left=right+1。继续右移,执行上述过程。最后会剩下最后一个单词没有反转。进行反转即可。
代码:
class Solution { //颠倒字符串中的单词
public:
void removeSpace(string& s) {
int slow = 0;
int fast = 0;
while (s.size() > 0 && fast < s.size() && s[fast] == ' ') { //前导空格
fast++;
}
for (; fast < s.size(); fast++) { //中间空格
if (fast > 0 && s[fast] == ' ' && s[fast - 1] == ' ') {
continue;
}
else {
s[slow++] = s[fast];
}
}
if (slow - 1 > 0 && s[slow - 1] == ' ') //尾随空格
slow--;
s.resize(slow);
}
void reverse(string&s, int begin, int end) {
int left = begin, right = end - 1;
while (left < right) { //反转
s[left] = s[left] ^ s[right];
s[right] = s[left] ^ s[right];
s[left] = s[left] ^ s[right];
left++;
right--;
}
}
string reverseWords(string s) {
removeSpace(s);
reverse(s, 0, s.size());
int left = 0, right = 0;
for (; right < s.size(); right++) { //反转单词
if (s[right] == ' ') {
reverse(s, left, right);
left = right + 1;
}
}
reverse(s, left, s.size()); //最后一个单词反转
return s;
}
};
int main()
{
string s = "a good example";
Solution solution;
string result = solution.reverseWords(s);
cout << result << endl;
return 0;
}