第2题 替换空格

题目描述:

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


解决思路:

题意很清楚,就是替换字符串,平常开发中会做的事情,我们通常会用replaceAll()来完成,显然也是行的通的。。

public class Solution {
    public String replaceSpace(StringBuffer str) {
        //排除特殊情况
        if (str == null ) {
            return null;
        }
        return str.toString().replaceAll(" ", "%20");
    }
}

但显然题目并不希望你这样做,而是希望能够实现一个类似的过程。。

所以理想的解决思路应该是这样的:

首先采用StringBuffer(或者StringBuilder)这种缓冲区来提高性能完成整个替换过程,而不希望在原有字符串的基础上,新开辟一个字符串空间完成替换(String是不可变量)。其次我们通过遍历这个字符串,如果当前索引处的字符为“ ”时,就进行替换,否则不变,替换的过程相当于在当前空格位置插入“%20”这个3个字符,所以需要将该位置后的所有字符后移。这样就存在两个问题,(1)因为替换后字符串长度肯定增加了,所以StringBuffer需要扩容(我们手动扩容避免自动扩容带来的性能浪费)(2)实现字符后移的效果,我们是从前往后,化石从后往前?这里分析一下两者的区别,如果采用从前往后遍历,那么替换一个位置的字符,当前索引位置处的字符都要逐个向后移动一次,有多个位置需要替换,就会右多次重复的后移,而从后往前遍历的话,只需要将字符赋值到新位置上就行,相当于每个字符只需要移动一次即可,显然后者效率更高。下面一张图便于理解。。

 所以确定了采用逆序遍历即可,我们判断原字符串中有几个空格,然后在进行扩容,“ ”替换成“%20”,每次替换多两个字符,所以扩容大小就是原长度+ 空格数*2。最后就是后移即可。

代码实现如下(Java版):

public class Solution {
    public String replaceSpace(StringBuffer str) {
        //排除特殊情况
        if (str == null ) {
            return null;
        }
        //统计原字符串长度
        int oldLength = str.length();
        //维护旧索引下标
        int oldIndex = oldLength - 1;
        //统计字符串中多少空格
        int spaceNum = 0;
        for (int i = 0; i < str.length(); i++) {
            if (str.charAt(i) == ' ') {
                spaceNum++;
            }
        }
        //如果没有空格的话,无需替换,直接返回原字符串即可
        if (spaceNum == 0) {
            return str.toString();
        }
        //计算出空格替换后的字符串长度并扩容
        int newLength = oldLength + spaceNum * 2;
        int newIndex = newLength - 1;
        str.setLength(newLength);
        //从后往前顺序替换空格
        char c ;
        while (oldIndex >= 0) {
            c = str.charAt(oldIndex);
            if (c == ' ') {
                //如果为空格替换
                str.setCharAt(newIndex--, '0');
                str.setCharAt(newIndex--, '2');
                str.setCharAt(newIndex--, '%');
            } else {
                //否则赋予原值
                str.setCharAt(newIndex--, c);
            }
            oldIndex--;
        }
        return str.toString();
    }
}

这种方式时间复杂度为O(n),常数系忽略。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值