剑指offer--替换空格

17 篇文章 0 订阅

记录《剑指offer》上的算法题。完整的代码例子可以在我的Github

这是一道有关字符串的问题。首先在C/C++中,会把常量字符串放到单独的一个内存区域中,当几个指针赋值给相同的常量字符串时,它们实际上会指向相同的内存地址;但如果用常量内存初始化数组,数组的地址是不相同的。

下面给出替换空格的题目:

请实现一个函数,把字符串中的每个空格替换成”%20”。例如输入“We are happy.”, 则输出”We%20are%20happy.”。

在网络编程中,对于含有特殊字符的URL参数,如空格,”#“等,可能导致服务器端无法获得正确的参数值。我们需要将这些特殊符号转换成服务器可以识别的字符,替换的规则是在’%’后面跟上ASCII码的两位十六进制的表示。比如空格的ASCII码是32,即十六进制的0x20,因此空格被替换成”%20”。

这里首先需要分两种情况,第一种是在原来的字符串上做替换;第二种是创建新的字符串并在新的字符串上做替换。现在假设是第一种情况,在原来的字符串上做替换并保证输入的字符串后面留有足够的空余内存。

最直观的做法是从头到尾扫描字符串,每一层碰到空格字符的时候做替换,由于需要将1个字符替换成3个字符,所以每次替换的时候,都要将空格后面的字符都往后移动两个字节,否则就有两个字符被替换了。因此,这种做法的时间复杂度是 O(n2)

上述做法是从前往后替换,现在可以换个思路,从后往前进行替换。首先是先遍历一遍字符串,计算字符串中空格的总数,由此计算出替换之后字符串的总长度,这里是每替换一个空格就需要增加两个字节的长度,因此替换之后的字符串长度应该是原来的长度加上两倍的空格数目。然后从后面开始复制和替换空格,需要准备两个指针P1和P2,P1指向当前字符串末尾,P2指向替换之后的字符串的末尾,然后向前移动P1,逐个把它指向的字符复制到P2指向的位置,而遇到空格的时候,P2就需要向前移动3格,因为需要复制过来的是3个字符,而P1还是移动一位。而当P2和P1都指向同一个位置的时候,说明所有空格都替换完毕了。

这种做法的时间复杂度是 O(n) ,效率是远高于第一种做法,下面给出这种做法的代码实现和测试例子。

#include<iostream>
using std::cout;
using std::endl;
using std::cin;

// 替换空格,length是字符数组string的总容量
void ReplaceBlank(char string[], int length){
    if (string == NULL || length <= 0){
        return;
    }
    // 字符串string的实际长度
    int originLength = 0;
    int numberOfBlank = 0;
    int i = 0;
    // 统计空格的数量和字符的数量
    while (string[i] != '\0'){
        ++originLength;
        if (string[i] == ' ')
            ++numberOfBlank;
        ++i;
    }
    // 替换空格后的字符串新长度
    int newLength = originLength + numberOfBlank * 2;
    if (newLength > length)
        return;

    int indexOfOriginal = originLength;
    int indexOfNew = newLength;
    while (indexOfOriginal >= 0 && indexOfNew > indexOfOriginal){
        if (string[indexOfOriginal] == ' '){
            string[indexOfNew--] = '0';
            string[indexOfNew--] = '2';
            string[indexOfNew--] = '%';
        }
        else{
            string[indexOfNew--] = string[indexOfOriginal];
        }
        indexOfOriginal--;
    }
}

// 测试
int main(void){
    char str[10] = " hello";
    char str2[10] = "he llo";
    char str3[10] = "hello ";
    char str4[30] = "We  are  happy.";
    char str5[30] = "helloWorld.";
    char *str6 = NULL;
    char str7[10] = "";
    char str8[10] = " ";
    char str9[20] = "     ";
    // 空格位于字符串的最前面
    cout << "origin: " << str;
    ReplaceBlank(str, 10);
    cout << ",--> " << str << endl;
    // 空格位于字符串的最后面
    cout << "origin: " << str2;
    ReplaceBlank(str2, 10);
    cout << ",--> " << str2 << endl;
    // 空格位于字符串的中间
    cout << "origin: " << str3;
    ReplaceBlank(str3, 10);
    cout << ",--> " << str3 << endl;
    // 字符串中有多个连续空格
    cout << "origin: " << str4;
    ReplaceBlank(str4, 30);
    cout << ",--> " << str4 << endl;
    // 输入的字符串没有空格
    cout << "origin: " << str5;
    ReplaceBlank(str5, 30);
    cout << ",--> " << str5 << endl;
    // 字符串是空指针
    ReplaceBlank(str6, 10);
    // 字符串是空字符串
    cout << "origin: " << str7;
    ReplaceBlank(str7, 10);
    cout << ",--> " << str7 << endl;
    // 字符串只有一个空格字符
    cout << "origin: " << str8;
    ReplaceBlank(str8, 10);
    cout << ",--> " << str8 << endl;
    // 字符串中只有多个连续空格
    cout << "origin: " << str9;
    ReplaceBlank(str9, 20);
    cout << ",--> " << str9 << endl;

    system("pause");
    return 0;
}

这种从后往前复制的思路还可以用在合并两个数组的情况。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

spearhead_cai

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

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

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

打赏作者

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

抵扣说明:

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

余额充值