题目三:替换空格

题目三:替换空格

请实现一个函数,将一个字符串中的每个空格替换成“%20”。

例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。

思路描述

如果是在原来的字符串上进行替换,就有可能覆盖修改在该字符串后面的内存;

如果是新创建的字符串并在新的字符串的上进行替换,那么我们可以自己分配足够的内存。

由于有两种不同的解决方案,我们应该向面试官问清楚,让他明确的高速我门它的需求。

思路一:暴力破解(创建新的字符串)

  /**
     * 暴力破解:遍历整个字符串逐项查找每个位置上字符是否等于 空字符;若为空字符则进行替换
     * 运行时间:22ms

     占用内存:9584k
     * @param str
     * @return
     时间复杂度为O(N);空间复杂度为O(n)
     */
    public static  String replaceSpace1(StringBuffer str) {
            //先把空格找出来,然后将空格处的位置进行替换;新生成一个对象
            StringBuilder stringBuilder = new StringBuilder();
            for(int i =0;i<str.length();i++){//遍历整个字符串
                if(str.charAt(i)==' '){//为空则置换
                    stringBuilder.append("%20");
                }else{
                    stringBuilder.append(str.charAt(i));
                }
            }
        return stringBuilder.toString();
    }

思路二:借助正则表达式

  /**
     * 使用正则表达式
     * @param str
     * @return
     */
    public String replaceSpace2(StringBuffer str) {
        return str.toString().replaceAll("\\s", "%20");
    }

思路三:从前往后遍历移动元素(时间复杂度为O(N*n))

最直观的做法就是遍历字符串,遇到 空格字符 就将其后面元素 依次向后移动两个位置

因为要有两个for循环,所以时间复杂度为O(n^2)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KILNIahp-1579335514784)(images/04.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9tbCBAUC-1579335514816)(images/05.png)]

  /**
        在字符串的基础上进行操作:从前往后  时间复杂度为O(n^2)
     */
    public static String replaceSpace3(StringBuffer str){
        int num = str.length();//字符串中的数量。动要变化
        //遍历所有字符
        for(int i=0;i<num;i++){
            //假如当前字符为空
            if(str.charAt(i)==' '){
                //当前空格字符之后的字符向后移动2位\
                for(int x=0;x<2;x++) {
                    int t = str.length() - 1;//从最后一个字符开始移动
                    while (t > i) {
                        char value = str.charAt(t);
                        str.replace(t+1,t+2,value+"");//往后挪动一位
                        t--;
                    }
                }
                str.replace(i,i+1,"%");//将%20插入
                str.replace(i+1,i+2,"2");
                str.replace(i+2,i+3,"0");
            }


        }
        return str.toString();
    }

思路四:从后往前,使用指针,定位出空白字符的数量

  1. 遍历字符串,统计出字符串中空白字符的总数,并计算出替换之后字符的长度

  2. 从字符串的后面开始复制和替换;

​ 2.1、首先准备两个指针:P1:指向原始字符的尾部;P2:指向新字符串的尾部

​ 2.2、若p1指向的字符不为空,则将p1处的字符拷贝到p2处 p1–;p2–;

​ 若p2指向的字符为空,则将p1向前移动一步p1–;将p2向前移动三个位置; 替换p2后的三个位置

​ 循环上述过程直到p1==p2

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CEZz1eNH-1579335514817)(images/06.png)]

/**
     * 从后往前遍历  :
     *      时间复杂度为O(n)
     * @param str
     * @return
     */
    public static String replaceSpace4(StringBuffer str){

        //先计算字符串中空字符的个数,然后为其分配内存 :原字符的长度+空格字符数量*2
        int spaceCharNum = 0;
        for(int i=0;i<str.length();i++){
            if(str.charAt(i)==' '){//发现空格字符
                //将空白字符数量+1
                spaceCharNum++;
            }
        }

        //设置替换后  字符串应为的长度
        str.setLength(str.length()+2*spaceCharNum);

        //定义两个指针,p1:指向原字符串的尾部
                      //p2:指向新生成的字符串的尾部
                            //多出来的空白字符适用来存储 %20的。
                            //从后往前遍历 :找到应该插入%20的位置
        int p1 = str.length()-2*spaceCharNum-1;
        int p2 = str.length()-1;

        //遍历字符串,当p1==p2时结束遍历
                //当p1不为空时,将p1位置的字符拷贝到p2处
                //当p1为空时,将p1向前移动一位,将p2向前移动3位,并将p2后的位置赋值为20%

        while(p1!=p2){//遍历字符串,当p1==p2时结束
            if(str.charAt(p1)!=' '){  //不为空
                str.replace(p2,p2+1,str.charAt(p1)+"");
                p1--;//p1与p2指针向前移动
                p2--;
            }else{
                p1--; //p1向前移动一个位置
                p2 -=3;//p2向前移动三个位置
                str.replace(p2+1,p2+4,"%20");
            }
        }


        return str.toString();


    }

在合并两个数组(包括字符串时),如果从前往后复制每个数字(或字符)则需要重复移动数字(或字符)多次,那么我们可以考虑从后往前复制,这样就减少移动的次数,从而提高效率

扩展:有序数组合并

两个排序数组 A1,A2* 内存在A1的末尾有足够的空余空间容纳A2.*

把A2中的数字插入到A1中并且所有排序是有序的

思路一:从前往后,遍历复制数字

 /**
     * 两个排序数组 A1,A2
     * 内存在A1的末尾有足够的空余空间容纳A2.
     * 把A2中的数字插入到A1中并且所有排序是有序的
     * @param A1
     * @param A2
     * @return
     */
    public static  int[] sort(int[] A1,int[] A2){

        for(int i=0;i<A2.length;i++){

            int j=0;
            for(j=0;j<A1.length;j++){
                if(A2[i]<A1[j]){//找到插入位置 j(包括j)之后的位置后移 一个位置
                   System.arraycopy(A1,j,A1,j+1,10-j);
                   A1[j]=A2[i];
                   break;
                }
            }
            //当前遍历的数据比A1中素有数据都打;直接将数据添加到数组末尾
            if(j==A1.length){
               A1[5+i-1]=A2[i];
            }

        }
        return A1;

    }

思路二:从后往前复制

  public static void merge(int[] A1, int[] A2, int lengthA1, int lengthA2){
            int indexA1 = lengthA1-1;//数组A1的末尾元素
            int indexA2 = lengthA2-1;//数组A2的末尾元素
            int indexMerged = lengthA1+indexA2-1;//合并之后的末尾元素;合并之后

            while(indexA1>=0&&indexA2>=0){//当没有比较晚
                if(A1[indexA1] >= A2[indexA2]){  //假如A1中的元素大
                    A1[indexMerged] = A1[indexA1]; //将A1中的从后往前数的位置赋值为 A1中的元素
                    indexMerged--;  //指针迁移
                    indexA1--;
                }else{  //假如A2中的元素大
                    A1[indexMerged] = A2[indexA2];
                    indexMerged--;
                    indexA2--;
                }
            }

            while(indexA1>=0){  //假如A1中海油剩余的元素
                A1[indexMerged] = A1[indexA1];
                indexMerged--;
                indexA1--;
            }

            while(indexA2>=0){ //A2中海油剩余的元素
                A1[indexMerged] = A2[indexA2];
                indexMerged--;
                indexA2--;
            }

        }

小结:上述合并字符串 或者从前往后复制数字的核心 就是分配出更多内存空间;我们可以转换为从后往前进行操作,确定每一个位置上应该放到数据为什么??

发布了107 篇原创文章 · 获赞 17 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/ZHOUJIAN_TANK/article/details/104031335