剑指offer_面试题4_替换空格(注意时间效率)

题目:请实现一个函数,把字符串中的每个空格替换成“%20”。

           例如:输入“We are happy.”,则输出“We%20are%20happy.”

 对于这个问题,初见,可能感觉会比较简单,但隐藏了很多陷阱,需要考虑全面。

陷阱1:由一个字符,替换为,三个字符,那么字符串肯定变长,需要考虑原字符串内存是否足够

陷阱2:空指针检查,不能忘记

陷阱3:时间复杂度很关键

最直观的做法(从前向后替换):从头到尾扫面字符串,每一次碰到空格字符的时候做替换。由于是把1个字符替换成3个字符,我们必须要把空格后面的所有字符都后移两个字节,否则就有两个字符被覆盖。

这样做的话,对于一个存在多个空格的字符串,很明显存在移动多次的字符。增加了时间复杂度。

这种做法代码如下:

/** 一般解法,时间复杂度O(n^2) */
void Replace_Blank2(char str[],int length)
{
    /**检查空指针*/
    if(NULL == str || length <= 0)
        return;

    int i, j, p1, p2;
    int new_len;
    int old_len;
    i = 0;
    j = 0;
    while(str[i] != '\0')
    {
        if(str[i] == ' ')
            j++;
        i++;
    }
    old_len = i;              // 原字符串的长度
    new_len = old_len + j*2;  // 新字符串的长度
    if(new_len >= length)     // 检查内存是否足够
        return;

    p1 = 0;                   // p1指向最开始
    p2 = old_len;             // p2指向结尾
    while(str[p1] != '\0')
    {
        if(str[p1] != ' ')    // 不为空格,指针向后移动一位
            p1++;
        else{                 // 由于是从前向后替换,因此碰到空格需要做两件事,一是先移位,二是后替换
            while(p2 > p1)
            {
                str[2+p2] = str[p2];  // 空格后面所有字符向后移动两位
                p2--;
            }
            old_len = old_len + 2;
            p2 = old_len;             // p2再次指向最后
            str[p1++] = '%';          // 空格替换
            str[p1++] = '2';
            str[p1++] = '0';
        }
    }
}

逆向思维做法:从后向前替换,先遍历整个字符串,得出空格总数,从而计算出替换后字符串的总长度。这样就知道了最后面的字符需要移动的总位数,就相当于将后面本来要移动多次的字符,一次性先移掉。然后从后向前替换空格。

这样所有字符都只需移动一次,时间复杂度大大降低。

如下图所示:

代码如下:

/** 时间复杂度O(n) */
void Replace_Blank(char str[],int length)
{
    if(NULL == str || length <= 0)
        return;

    int i, j, p1, p2;
    int len_of_str;     // 变量名要简单明了
    int num_of_blank;
    int new_len_of_str;

    i = 0;
    j = 0;
    while(str[i] != '\0')
    {
        if(' ' == str[i])
            j++;
        i++;
    }
    len_of_str = i;
    num_of_blank = j;
    new_len_of_str = len_of_str + num_of_blank*2;

    if(new_len_of_str >= length)
        return;

    p2 = new_len_of_str;
    p1 = len_of_str;

    while(p1 >= 0 && p2 > p1)
    {
        if(str[p1] != ' ')
        {
            str[p2--] = str[p1--];
        }
        else{
            str[p2--] = '0';
            str[p2--] = '2';
            str[p2--] = '%';
            p1--;
        }
        //p1--;
    }
}

主函数如下:(可以添加其他测试用例)

int main()
{
    char str[20] = "We are happy.";
    int len = sizeof(str);
    Replace_Blank(str,len);

    cout << str << endl;
    return 0;
}

结果如下:


/*点滴积累,我的一小步O(∩_∩)O~*/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值