​​151. 翻转字符串里的单词​​

给你一个字符串 ​​s​​ ,逐个翻转字符串中的所有 单词 。

单词 是由非空格字符组成的字符串。​​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"
解释: 如果两个单词间有多余的空格,将翻转后单词间的空格减少到只含一个。

示例 4:

输入: s = "  Bob    Loves  Alice   "
输出: "Alice Loves Bob"

示例 5:

输入: s = "Alice does not even like bob"
输出: "bob like even not does Alice"

提示:

  • ​1 <= s.length <= 104​
  • ​s​​​ 包含英文大小写字母、数字和空格​​' '​
  • ​s​​ 中至少存在一个单词

思路


题述中要考虑空格字符的三种位置:开头、中间、结尾,所以可以先去除重复的空格字符,然后将所有的字符进行反转,再对每一个单词中的字符进行反转。


算法步骤

  • 去除多余空格符
  • 反转去除多余空格符的字符串
  • 对反转后的字符串,判断每个单词的起止位置,将单词中的字符进行反转

代码

class Solution
{
public:
string reverseWords(string s)
{
// 去除多余的空格
removeExtraSpaces1(s);

// 反转字符串
reverse(s, 0, s.size() - 1);

// 反转后的每个单词的起始位置与结束位置
int start = 0, end = 0;
bool entry = false;
for (int i = 0; i < s.size(); i++)
{
if (!entry)
{
// 单词的起始位置
start = i;
// 进入单词区间
entry = true;
}

// 出现的空格表示两个单词的分割符
if (entry && s[i] == ' ' && s[i - 1] != ' ')
{
// 确定单词的结束位置
end = i - 1;
// 单词区间结束
entry = false;
// 反转该区间(单词区间)的字符
reverse(s, start, end);
}

// 判断最后一个结尾词之后没有空格的情况
if (entry && (i == (s.size() - 1)) && s[i] != ' ')
{
// 确定单词的结束位置
end = i;
// 单词区间结束
entry = false;
// 反转单词区间的字符
reverse(s, start, end);
}
}
return s;
}

// 移除多余空格,时间复杂度为O(n^2)
// erase的时间复杂度为O(n)
void removeExtraSpaces(string &s)
{
for (int i = s.size() - 1; i > 0; i--)
{
// 判断相邻的字符是否都是空格,如果是空格就erase掉
if (s[i] == s[i - 1] && s[i] == ' ')
{
s.erase(s.begin() + i);
}
}

// 删除最前面的空格
if (s.size() > 0 && s[0] == ' ')
{
s.erase(s.begin());
}
//删除末尾的空格
if (s.size() > 0 && s[s.size() - 1] == ' ')
{
s.erase(s.begin() + s.size() - 1);
}
}

// 使用双指针来移除多余的空格
// 快指针fast,满指针slow
// 时间复杂度为O(n)
void removeExtraSpaces1(string &s)
{
// 定义快慢指针
int fast = 0, slow = 0;
// 去除最前面的空格
while (s.size() > 0 && fast < s.size() && s[fast] == ' ')
{
fast++;
}
for (; fast < s.size(); fast++)
{
//去掉字符串中间部分多余的空格
if (fast - 1 > 0 && s[fast - 1] == s[fast] && s[fast] == ' ')
{
continue;
}
else
{
// 将字符向前移动直到移动到最后(最后一个可能空格字符也可能不是)
s[slow++] = s[fast];
}
}
// 最后如果有空格的话,通过resize的方式过滤掉
if (slow - 1 > 0 && s[slow - 1] == ' ')
{
s.resize(slow - 1);
}
else
{
s.resize(slow);
}
}

// 反转字符串
void reverse(string &s, int start, int end)
{
for (int i = start, j = end; i < j; i++, j--)
{
swap(s[i], s[j]);
}
}
};

【力扣-字符串】3、反转字符串里的单词(151)_C++