[剑指-Offer] 5. 替换空格(反向思维、代码优化、多方法)

1. 题目来源

链接:LeetCode 替换空格
链接:NowCoder 替换空格
来源:LeetCode——《剑指-Offer》专项
来源:NowCoder——《剑指-Offer》专项

2. 题目说明

请实现一个函数,把字符串 s 中的每个空格替换成"%20"。

示例 1:

输入:s = “We are happy.”
输出:“We%20are%20happy.”

限制:

  • 0 <= s 的长度 <= 10000

3. 题目解析

3.1 方法一:string大法好

来自LeetCode 替换空格 string 简单操作直接搞定,不是重点,不解释。

参见代码如下:

// 执行用时 :0 ms, 在所有 C++ 提交中击败了100.00%的用户
// 内存消耗 :8.4 MB, 在所有 C++ 提交中击败了100.00%的用户

class Solution {
public:
    string replaceSpace(string s) {
        string str;
        string tmp = "%20";
        for (auto& e : s) {
            if (e != ' ')
                str.push_back(e);
            if (e == ' ')
                str += tmp;
        }
        return str;
    }
};

3.2 方法二:从前往后移动替换

朴素思想,从前往后遍历字符串,遇到空格,将空格后的字符串统一后移两位,留出两个空格,依次添加 %20 即可。但是频繁的向后搬运空格的操作,势必每次遍历空格后的字符串,假设字符串长度为 n ,对于每个空格字符,需要移动后面 O ( n ) O(n) O(n) 个字符,,因此对于 O ( n ) O(n) O(n) 个空格字符的字符串而言,时间复杂度为 O ( n 2 ) O(n^2) O(n2)

虽说完成了要求,但是时间复杂度很不理想~,在此不列代码,没啥意义。

3.3 方法三:从后往前移动替换

来自:NowCoder 替换空格

这个思想厉害了

  • 首先遍历字符串统计得到所有的空格数为 cnt,一个空格代表向后移动 2 位,那么就直接在后面开辟 2 * cnt 的空间
  • 采用双指针,一个在原字符串尾部的\0一个在新开辟空间的尾部。
  • 依次从后往前进行比遍历
  • 遇到空格了,就在尾指针处添加02%,由于是从后向前遍历,也就逆序添加,尾指针跟着向前走,始终指向空格
  • 遇到有效字符了,就将头指针指向字符搬给尾指针所在空格即可,并将尾指针、头指针同时向前 +1
  • 当头、尾相遇,此时添加完毕,返回即可

下面这张图很好的阐述了这个思想:

在这里插入图片描述
这样操作,遇到空格了,字符串仅需要搬运一次,时间复杂度为 O ( n ) O(n) O(n) ,也是满意的做法了。

class Solution {
public:
void replaceSpace(char *str,int length) {
        //遍历一边字符串找出空格的数量
        if (str == NULL || length < 0)
            return;
        int i = 0;
        int oldnumber = 0;   //记录以前的长度
        int replacenumber = 0;//记录空格的数量
        while (str[i]!='\0') {
            oldnumber++;
            if (str[i]==' ') {
                replacenumber++;
            }
            i++; 
        }
        int newlength = oldnumber + replacenumber * 2;//插入后的长度
        if(newlength > length)//如果计算后的长度大于总长度就无法插入
            return;
        int pOldlength = oldnumber; //注意不要减一因为隐藏个‘\0’也要算里
        int pNewlength = newlength;
        while (pOldlength >= 0 && pNewlength > pOldlength)//放字符
        {
            if (str[pOldlength] == ' ') //碰到空格就替换
            {
                str[pNewlength--] = '0';
                str[pNewlength--] = '2';
                str[pNewlength--] = '%';

            }
            else //不是空格就把pOldlength指向的字符装入pNewlength指向的位置
            {
                str[pNewlength--] = str[pOldlength];

            }
             pOldlength--; //不管是if还是elsr都要把pOldlength前移
           }
    }
};

3.3 方法四:坐标关系、统计空格数

来自:NowCoder 替换空格

还是遍历字符串,统计空格数 count。此时依旧从后向前进行遍历,如果 str[i] != ' ',那么就将字符直接进行移动 str[i + 2 * count] = str[i];,如果遇到空格,依旧进行坐标关系填充 %20即可。思想和方法三一致,时间复杂度为 O ( n ) O(n) O(n)

class Solution {
public:
    void replaceSpace(char *str,int length) {
        int count = 0;
        for (int i = 0; i < length; ++i){
            if (str[i] == ' ')
                ++count;
        }
        for (int i = length - 1; i >= 0; --i) {
            if (str[i] != ' ') {
                str[i + 2 * count] = str[i];
            }
            else {
                --count;
                str[i + 2 * count] = '%';
                str[i + 2 * count + 1] = '2';
                str[i + 2 * count + 2] ='0';
            }
        }
    }
};
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Ypuyu

如果帮助到你,可以请作者喝水~

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

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

打赏作者

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

抵扣说明:

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

余额充值