剑指Offer-02-替换空格

题目

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

解析

思路一

很可能陷入误区,以为只要返回的字符串符合题意就可以,其实并不然。这道题其实考察的是在原址上进行字符串替换操作。所以下面的代码是错误!

 str.toString().replaceAll(" ", "%20");

思路二

原址上的操作的最终目的也是改变原字符串啊,所以转变思路为另申请一个内存空间,在该空间进行字符换替换操作,待完成替换后把结果拷贝到原址上,这样也可以达到原址上字符串操作的效果,有种投机取巧的赶脚。

    /**
     * 常规解法,开辟一个新的空间进行处理结果,最后再copy到原空间上。
     * @param str
     * @return
     */
    public static String replaceSpace1(StringBuffer str) {
        String s = str.toString();
        StringBuilder sb = new StringBuilder();
        for(int i = 0; i < s.length(); i++){
            if(s.charAt(i) == ' '){
                sb.append("%20");
            }else {
                sb.append(s.charAt(i));
            }
        }
        str.delete(0, str.length());
        str.append(sb);
        return str.toString();
    }

思路三

即是正规的原址操作了,观察我们的字符串后,发现替换后的字符串的总长度为原长度 + 2 * 空格数组。所以我们可以考虑扩展我们的字符串的长度,然后通过插入和移动元素来完成。
这里如果我们从头到尾进行依次处理插入,会发现每处理一次空格,后面的字符都要往后移动2格,复杂度为O(n的平方)。那有没有其他方法可以直接就确定每个字符的最终位置,从而避免每次都要移位呢?
我们从尾部处理就可以啊,你想啊,最后一个字符必然处于扩展后字符串的最后一位,所以我们直接从后处理,直接确定每个字符最终的位置。

We are happy
We%20are%20happy
观察发现,y向后的移动位数为(y之前的空格数)*2
e向后移动的位数为(e之前的空格数)* 2
所以需要先统计出空格数,然后根据当前空格数,
确定需要移动位数,空格的情况移动的位数所需的空格数就不必包含本身了。
比如倒数第一个空格向后移动的位数为它之前空格数*2,然后该位置需要替换为%, 之后依次2,0

代码如下:

    public static String replaceSpace2(StringBuffer str) {
        int spaceNum = 0;
        for(int i = 0; i < str.length(); i++) {
            if(str.charAt(i) == ' ') {
                spaceNum++;
            }
        }
        int oldLength = str.length();
        str.setLength(oldLength + spaceNum * 2);
        for(int i = oldLength - 1; i >= 0; i--){
            if(str.charAt(i) != ' ') {
                str.setCharAt(i + 2 * spaceNum, str.charAt(i));
            }else {
                spaceNum--;
                int length = i + 2 * spaceNum;
                str.setCharAt(length, '%');
                str.setCharAt(length + 1, '2');
                str.setCharAt(length + 2, '0');
            }
        }
        return str.toString();
    }

思路四

也就是《剑指Offer》的标准解法了。就是直接用2个尾指针就可以了,依次对号入座,简单粗暴。

  /**
     * 剑指Offer上的标准解法
     * @param str
     * @return
     */
    public static String replaceSpace3(StringBuffer str) {
        int spaceNum = 0;
        for(int i = 0; i < str.length(); i++) {
            if(str.charAt(i) == ' ') {
                spaceNum++;
            }
        }
        int oldLength = str.length();
        str.setLength(oldLength + spaceNum * 2);
        int newLength = str.length();
        for(oldLength--, newLength--; oldLength >= 0 && oldLength < newLength; oldLength--){
            if(str.charAt(oldLength) != ' ') {
                str.setCharAt(newLength--, str.charAt(oldLength));
            }else {
                str.setCharAt(newLength--, '0');
                str.setCharAt(newLength--, '2');
                str.setCharAt(newLength--, '%');
            }
        }
        return str.toString();
    }  

拓展

  • 数组合并,数组拓展问题,都可以从尾部开始

你可能感兴趣的:(不刷题心里难受,剑指Offer)