【算法】替换空格

133 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第2天,点击查看活动详情

题目

实现一个函数可以将字符串中每个空格替换为"%20"。举例输入"We are Family",进过函数处理后输出"We%20are%20Family"。

解题思路

  1. 每个空格替换为%20等同于1个字符替换成3个字符。
  2. 字符串总长度变长了。

若使用已有String替换方法实现本题解法是简单的,利用replace(a,b)将a替换成b即可。但先不考虑采用api解题方式自行实现方法来满足题目要求。

StringBuilder res = new StringBuilder();
for(Character c : s.toCharArray())
{
    if(c == ' ') res.append("%20");
    else res.append(c);
}
return res.toString();

PS:面向对象开发真香~

Char遍历法

char是字符类型,String是字符串类型;char是基本类型,String是类;char用''表示,String用""表示。在Java中通过遍历String字符串每个字符来找到空格并填写新字符来实现。

  • 官方解题方式
        int length = s.length();
        char[] array = new char[length * 3];
        int size = 0;
        for (int i = 0; i < length; i++) {
            char c = s.charAt(i);
            if (c == ' ') {
                array[size++] = '%';
                array[size++] = '2';
                array[size++] = '0';
            } else {
                array[size++] = c;
            }
        }
        String newStr = new String(array, 0, size);
        return newStr;

为了满足所有空格需求对整体字符串做扩展满足全为空格的情况,缺点就是占用空间大了。

  • 自写解题方式
        int length = s.length(); //总长度
        int size = 0; // 空格数
        for(int i = 0; i < s.length();i++){
            if(s.charAt(i)==' '){
               size++;
            }
        }
        char[] newChar = new char[length + size * 2]; //新字符串长度
        int p = 0;
        for(int i = 0; i < s.length();i++){
            if(s.charAt(i)==' '){
               newChar[p++] = '%';
               newChar[p++] = '2';
               newChar[p++] = '0';
            }else{
                newChar[p++] = s.charAt(i);
            }
        }
        return new String(newChar);

对以上解法做了小小优化,先遍历一次字符串得到空格数,根据空格数再扩展实际字符串长度空间大小。

指针法

  1. 同理先遍历字符串获取空格数,每个空格长度加2
  2. 准备i,j两个指针分别指向原字符串末尾和新字符串末尾。
  3. 移动i指针逐个字符复制到新字符串中,直到碰到空格。
  4. i遇到空格时j中插入%20,j指针往前移动3位,i再向前一位。
  5. 直到i和j指向同一位置表示空格替换结束。
      	int count = 0; // 统计空格的个数
        int oldLength = s.size();
        for (int i = 0; i < s.size(); i++) {
            if (s[i] == ' ') {
                count++;
            }
        }
        s.resize(s.size() + count * 2);// 新长度
        int length = s.size();
        // 从后往前替换空格为"%20"
        for (int i = length - 1, j = oldLength - 1; j < i; i--, j--) {
            if (s[j] != ' ') {
                s[i] = s[j];
            } else {
                s[i] = '0';
                s[i - 1] = '2';
                s[i - 2] = '%';
                i -= 2;
            }
        }
        return s;

原生算法(骚操作)

return s.replace(" ", "%20");

在Android中replace方法实现底层有Native来完成算法。

    public String replace(char oldChar, char newChar) {
        // BEGIN Android-changed: Replace with implementation using native doReplace method.
        if (oldChar != newChar) {
            final int len = length();
            for (int i = 0; i < len; ++i) {
                if (charAt(i) == oldChar) {
                    return doReplace(oldChar, newChar);
                }
            }
        }
        // END Android-changed: Replace with implementation using native doReplace method.
        return this;
    }
  	@FastNative
    private native String doReplace(char oldChar, char newChar);

在JavaSDK中String的替换方法内部实现有正则参与。

replacereplaceAll
该副本将字符串中所有出现的target子字符串都替换成replacement。改副本将字符串中所有出现的满足正则表达式regex的子字符串都替换成replacement。

但是两者性能上存在较大差异,相较而言replace比replaceAll耗时更短效率更高(主要是正则处理会慢些)。在简单替换字符串方式上尽量采用replace实现,对于复杂需要使用正则时才推荐使用replaceAll。