剑指offer(5 替换空格) 题解

剑指offer(5 替换空格) 题解

微信搜索【程序员画工师】关注更多Java编程技术、数据结构与算法、面试题相关内容。

题目

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

思路

最简单的做法就是从头到尾扫描字符串,每次碰到空格字符的时候就进行替换。创建新的StringBuffe对象(StringBuffer是线程安全的,每一个方法都加了锁,而StringBuilder是非线程安全的,方法没有加锁,如果采用StringBuilder对象则会快一点),遍历原字符串,当为空格时,替换为"%20",当不是空格的时候,复制原来位置上的字符串,时间复杂度为o(n),由于创建了新的对象占用了内存空间,是空间换时间的方法。或者Java string的replaceAll方法即可实现替换。

上代码

public class Solution {
    public String replaceSpace1(StringBuffer str) {
      return str.toString().replaceAll(" ","%20");
    }
    public String replaceSpace2(StringBuffer str) {
        int strLen = str.toString().length();
        StringBuffer strReplaced = new StringBuffer();
        for(int i = 0;i<strLen;i++){
            if(str.charAt(i) == ' '){
               strReplaced.append("%20");
            }else {
               strReplaced.append(str.charAt(i));
            }
        }
        return strReplaced.toString();
    }
}

剑指解法

如果不允许创建新的内存空间,只给定一个数组来进行替换的话,碰到一个空格,就加入"%20",于是可以从头到尾遍历字符串,碰到空格,首先将后面的所有字符串往后移动2个字符,这样才能空出3个字符位置插入字符“%20”,对于一个长度为n的字符串,对每个空格,需要移动后面O(n)个字符,因此包含n个空格的字符串,总的时间复杂度为O(n*n)。

思考:那有没有更优化的解法呢?

我们可以从后往前开始替换,首先遍历一遍字符串,统计出空格的个数,并由此能够计算出替换之后的字符串的长度。接着再次从后往前遍历字符串,同时设置两个索引P1和P2,P1指向原始字符串末尾,P2指向替换之后的字符串末尾。我们向前移动P1,逐个把它指向的字符复制到P2指向的位置,直到碰到第一个空格为止。然后把P1向前移动一格,在P2之前插入字符串“%20”,同时P2向前移动3格。重复此过程,直到所有的空格都已替换完。这样只需要扫描一遍,时间复杂度为O(n)。
移动示意图如下:
剑指offer(5 替换空格) 题解_第1张图片

剑指解法C++版代码

public:
  void replaceSpace(char *str,int length) {
    if(str == NULL && length <= 0){
            return;
        }
               /*original_length为字符串str的实际长度*/
        int original_length = 0;      //原始长度
        int number_blank = 0;        //空格数
        int i;
        while(str[i++] != '\0'){        //遍历字符串
            ++original_length;        //长度+1
            if(str[i] == ' '){
                ++number_blank;        //遇到空格+1
            }
        }
        /*new_length为把空格替换成'%20'之后的长度*/
        int new_length = original_length + 2 * number_blank;
        
        int index_original = original_length;  //原始字符串末尾索引值
        int index_new = new_length;        //计算长度后的字符串末尾索引值
        
        /*index_original指针开始向前移动,如果遇到空格,替换成'%20',否则进行复制操作*/
        while(index_original >= 0 && index_new > index_original){
            if(str[index_original] == ' '){
                str[index_new--] = '0';
                str[index_new--] = '2';
                str[index_new--] = '%';
            }
            else{
                str[index_new--] = str[index_original];
            }
            --index_original;
        }
  }
};

附剑指解法Java版代码供读者参考

public class Solution {
    public String replaceSpace(StringBuffer str) {
        int lengthOriginal = str.toString().length(); //原始长度
        int blankNum = 0; //空格数
        //计算空格数
        for(int i = 0;i<lengthOriginal;i++){
            if(str.charAt(i) == ' '){
                blankNum ++ ;
            }
        }
        int lengthFinal = str.toString().length() + 2 * blankNum; //替换后的字符串长度
        int indexOriginal = lengthOriginal - 1;//原始字符串的末尾索引
        int indexFinal = lengthFinal - 1;//替换后字符串的末尾索引
        char[] array = new char[lengthFinal];  //数组
        for(int i = 0;i<lengthOriginal;i++){ //复制到数组中
            array[i] = str.charAt(i);
        }
        while(indexOriginal >= 0 && indexOriginal != indexFinal){
            if(array[indexOriginal] == ' '){
                array[indexFinal--] = '0';
                array[indexFinal--] = '2';
                array[indexFinal--] = '%';
            }else{
                array[indexFinal--] = array[indexOriginal];
            }
            indexOriginal--;  // 从后先前遍历
        }
        String strReplaced = "";
        for(char i : array){
            strReplaced = strReplaced + String.valueOf(i);
        }
        return strReplaced;
    }
}

References

[1]:《剑指offer(第二版)》 何海涛著

程序员画工师公众号,欢迎交流
在这里插入图片描述

你可能感兴趣的:(剑指offer,数据结构,算法)