【JZ73 翻转单词序列】

描述

牛客最近来了一个新员工Fish,每天早晨总是会拿着一本英文杂志,写些句子在本子上。同事Cat对Fish写的内容颇感兴趣,有一天他向Fish借来翻看,但却读不懂它的意思。例如,“nowcoder. a am I”。后来才意识到,这家伙原来把句子单词的顺序翻转了,正确的句子应该是“I am a nowcoder.”。Cat对一一的翻转这些单词顺序可不在行,你能帮助他么?

数据范围: 1 ≤ n ≤ 100
进阶:空间复杂度 O(n) ,时间复杂度 O(n) ,保证没有只包含空格的字符串

示例1

输入: "nowcoder. a am I"

返回值: "I am a nowcoder."

示例2

输入: ""

返回值:""

方法一: 原地操作法

解题思路:将后面的字符插入到前面。

主要思路:

  1. 使用两个指针:cur_end与 cur_insert , cur_end表示当前字符串末尾位置,cur_insert表示当前插入位置。

  2. 从尾至头处理str,cur_end分为三种情况

    1. 如果cur_end指向的是空字符且上次处理的字符非空,那么将cur_end指向的字符插入到cur_insert同时删除cur_end所指字符。
    2. 如果cur_end指向非空字符,那么cur_end指向的字符插入到cur_insert同时删除cur_end所指字符。
    3. 如果cur_end指向空字符且上一次处理的字符也为空字符,那么直接删除cur_end所指字符。

代码

class Solution {
public:
    string ReverseSentence(string str) {
        if(str=="") return str;
        int cur_insert = 0; //插入位置
        int cur_end = str.size()-1;
        int former_pro = 1;  //上次处理的字符是否为空格
        int num = 0; //处理个数;
        for(int i = str.size();i>0;i--)
        {
            if(former_pro && str[cur_end] ==' ')
            {
                str.erase(cur_end--,1);
                former_pro = 1;
            }
            else if(!former_pro && str[cur_end]==' ')
            {
                cur_insert = num++;
                str.insert(cur_insert++,1,str[cur_end++]);
                str.erase(cur_end--,1);
                former_pro = 1;
            }
            else
            {
                num++;
                //连续的单词插入位置不能变,不然单词就会是反的
                str.insert(cur_insert,1,str[cur_end++]);
                str.erase(cur_end--,1);
                former_pro = 0;
            }
        }
        return str;
        
    }
};

运行时间:6ms
超过0.97% 用C++提交的代码
占用内存:572KB
超过19.23%用C++提交的代码
复杂度分析:时间复杂度:O(N)
空间复杂度:O(1)

方法二:双指针

解题思路: 利用两个指针标识一个单词。

主要思路:

  1. 从尾往头遍历 使用left表示一个单词的起始位置,right表示一个单词的终止位置。

  2. 当遇到空格left与right同时向前移动,当遇到字符只有left向前移动,截取[left+1,right] 子串。

  3. 拼接截取下的字符串。

int left = str.size() - 1;
        int right = str.size() - 1;
        string result = "";
        while (left >= 0)
        {
            while (str[left] == ' ')
            {
                --left;
                --right;
                if (left < 0) //越界
                {
                    break;
                }
            }
            if (left < 0) //越界
            {
                break;
            }
            while (str[left] != ' ')
            {
                --left;
                if (left < 0) //越界
                {
                    break;
                }
            }
            result = result + str.substr(left + 1, right - left) + " ";
            right = left;
        }
        return result.substr(0, result.size() - 1); // 结果后面会多一个空格

运行时间:5ms
超过2.06% 用C++提交的代码
占用内存:528KB
超过24.35%用C++提交的代码
复杂度分析:时间复杂度: O(N)
空间复杂度: O(N)

方法三:使用库函数stringstream

首先需要进行预处理,判断输入字符串是不是全部空格,如果是,直接输出字符串。否则,我们看如下图:
在这里插入图片描述
由图片可知,我们只需要先把每个单词拆分出来,然后以单词为翻转单元,即可得到结果串。
实现方式:
我们用stringstream可以实现拆分每个单词,具体代码如下:

class Solution {
public:
    string ReverseSentence(string str) {
        // 预处理
        if (str.empty()) return str;
        int i = 0, sz = str.size();
        while(i < sz && str[i] == ' ') ++i;
        if (i == sz) return str;
        istringstream ss(str);
        vector<string> ret;
        string s;
        // 拆分单词
        while (ss >> s) 
            ret.push_back(s);
        reverse(ret.begin(), ret.end());
        ostringstream oss;
        // 合并成字符串
        for (int i=0; i<ret.size()-1; ++i)
            oss << ret[i] << ' ';
        oss << ret.back();
        return oss.str();
        
    }
};

运行时间:3ms
超过31.79% 用C++提交的代码
占用内存:700KB
超过12.09%用C++提交的代码

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

千北@

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值