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

481 阅读2分钟

「这是我参与11月更文挑战的第9天,活动详情查看:2021最后一次更文挑战

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]);
        }
    }
};

image.png