剑指Offer58-Ⅰ.翻转单词顺序

  • 题目:剑指Offer58-Ⅰ.翻转单词顺序
    输入一个字符串s表示一句若干单词构成的一句话;
    s可能前面,后面,或单词之间有若干空格;
    需要将s的每个单词顺序翻转,但每个单词自身的字母顺序不能翻转;
    最后得到的字符串首尾不能有空格,且字母之间的空格只留一个;

  • 思路:
    1.快慢双指针:时间O(n):只需快指针从尾遍历到头,空间O(n):额外需要一个字符串res,最坏情况下,s没有多余空格,因此res的大小和s相同;
    从后往前划分单词,每找到一个单词[ i + 1,j ]就放到res后面,并添加一个空格作为单词之间的空隙;
    res的最后一个单词的后面多了一个空格,需要删掉;但有个特例是s本身只有空格,不存在任何一个单词,因此res也没有添加过单词和作为空隙的一个空格,因此仅当res不为空时,才需要删除空格操作;

class Solution {
public:
    string reverseWords(string s) {
        int n = s.size();
        if (n == 0) return s;

        string res;
        int i = n - 1, j = n - 1;
        while (i >= 0) {
            while (i >= 0 && s[i] == ' ') --i;
            if (i >= 0) j = i;//进入这个分支,说明找到了一个单词末尾
            else continue;//说明找不到单词了

            while (i >= 0 && s[i] != ' ') --i;//确定这个单词的范围[i + 1, j]
            for (int k = i + 1; k <= j; ++k) res.push_back(s[k]);
            res.push_back(' ');//每个单词后面补一个' '
        }
        //特殊情况:如果字符串s一个单词都没有全是空格,那么res为空,就不需要删除' '
        if (!res.empty()) res.pop_back();//最后一个单词的后面的' '是多余的; 

        return res;
    }
};

2.双指针原地修改:时间O(n),空间O(1):因为是原地修改,因此没有使用额外空间
在s上原地修改;
先去除首尾,中间的多余空格,并用resize保留有用的部分;
整体翻转 + 每个单词局部翻转:以此实现所有单词顺序翻转,但每个单词内的字母顺序不变;

class Solution {
public:
    string reverseWords(string s) {
        int n = s.size();
        if (n == 0) return s;

        int i = 0, j = 0;//快指针i,慢指针j
        while (i < n && s[i] == ' ') ++i;//跳过开头的空格
        if (i == n) return "";//说明s只有空格,没有单词

        while (i < n) {//去掉单词间多余的空格,每个单词后面若有多个空格,只剩下一个
            if (i > 0 && s[i] == s[i -1] && s[i] == ' ') {
                ++i;
                continue;
            }
            s[j++] = s[i++];
        }
        //若最后一个单词后面本身没空格,自然j停在最后一个单词的下个位置;
        //若最后一个单词后面有若干空格,自然j停在最后一个单词的下下个位置,因为下个位置的空格被保留
        if (s[j - 1] == ' ') s.resize(j - 1);
        else s.resize(j);

        reverse(s.begin(), s.end());//整体翻转
       
        i = 0, j = 0;//重新初始化i,j,n
        n = s.size();
        while (i < n) {//每个单词局部翻转
            while (i < n && s[i] != ' ') ++i;//i停在一个单词的下位置,即划分出一个单词[j, i - 1]
            reverse(s.begin() + j, s.begin() + i);
            i++;//跳过单词间的那个空格,指向下个单词的首字母
            j = i;//慢指针j指向单词首字母,下次循环中i去确定该单词的截止位置
        }

        return s;
    }
}; 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值