zoukankan      html  css  js  c++  java
  • 数据结构-字符串

    字符串是由若干字符组成的序列。字符串在编程时使用的频率非常高。

    C/C++中每个字符串都以为结尾,这样我们就能很方便的找到字符串的最后尾部。但由于这个特点,每个字符串中都有一个额外字符的开销,很容易造成字符串越界

    例如

    char str[10];
    strcpy(str,"0123456789");

    看起来只有10个字符,但是要正确的复制该字符串,至少需要一个长度为11的数组

    为了节省内存,C/C++把常量字符串放到一个单独的内存区域。当几个指针赋值给相同的常量字符串时,他们实际上会指向相同的内存地址。但用常量内存初始化数组,情况却有所不同。

    int judge(){
      char str1[]="hello world";
      char str2[]="hello world";
      
      char* str3="hello world";
      char* str4="hello world";
      
      if(str1==str2){
        printf("str1 and str2 are same
    ");
      }
      else{
        printf("str1 and str2 are not same
    ");
      }
      
      if(str3==str4){
        printf("str3 and str4 are same
    ");
      }
      else{
        printf("str3 and str4 are not same
    ");
      }
      return 0;
    }

    str1和str2是两个字符串数组,创建地址不同,后来在赋值,所以str1和str2不同

    str3和str4是两个指针,无需为他们分配内存,只需要把他们指向hello world在内存中的地址就可以了。由于hello world是常量字符串,他在内存中只有一个拷贝,因此str3和str4只想同一个地址,所以比较str3和str4的值得到的结果相同

     

    面试题5.替换空格

    题目:请实现一个函数,把字符串中每个空格替换成%20,例如"We are happy"替换为"We%20are%20happy"

    思路:对于空格,#等我们需要将这些特殊符号转换成服务器可以识别的字符。转换的规则是在%后面加上ASCII码的两位十六进制的表示。比如空格ASCII码是32,即十六进制的0x20,因此空格被替换为%20,同理#的ASCII码为35,十六进制0x23,URL中被替换为%23

    本题中原来是一个空格字符,替换后变成%,2,0三个字符,那么这个字符串会变长。如果是在原来的字符串上进行替换,就有可能覆盖修改在该字符串后面的内存。如果是创建新的字符串并在新的字符串上进行替换,就可以分配足够的内存。

    ①从前往后替换,每次添加%20就要把后面的字符往后移动,时间复杂度O(n^2)

    ②从后往前替换,遍历一遍字符数组,有一个空格就在后面加上2长度,以此计算出要往后的总长度,We are happy长度为14(包括)里面有两个空格,因此替换后为18,时间复杂度为O(n)

    而在Java里面一切都是对象,是对象的话,字符串肯定就有长度,即然有长度,编译器就可以确定要输出的字符个数,当然也就没有必要去浪费那1字节的空间用以标明字符串的结束了。

    使用双标记,一个标记指向被移动的字符,一个标记指向移动目的地,而他们二者的间距就是一个单词的长度

    public class spaceReplace {
        public static void spaceReplace(String strOld,int len){
            char[] chs =new char[len];
            char[] ch = strOld.toCharArray();
            for (int i = 0; i < ch.length; i++) {
                chs[i] = ch[i];
            }
    
            int strOldLen = 0;
            int blackString = 0;
            if(chs==null || len<=0)
            {
                new NullPointerException();
            }
    
            int i=0;
            while(chs[i]!=''){
                strOldLen++;
                if(chs[i]==' '){
                    blackString++;
                }
                i++;
            }
            //将空格转换成%20字符的长度
            int strNewLen = strOldLen + blackString*2;
            if(strNewLen>len){
                new ArrayIndexOutOfBoundsException();
            }
    
            int indexOfOld=strOldLen;//指向''
            int indexOfNew=strNewLen;
    
            while(indexOfOld>0 && indexOfNew>indexOfOld){
                if(chs[indexOfOld] == ' '){
                    chs[indexOfNew--] = '0';
                    chs[indexOfNew--] = '2';
                    chs[indexOfNew--] = '%';
                }
                else{
                    chs[indexOfNew--] = chs[indexOfOld];
                }
                --indexOfOld;
            }
            for (char c : chs) {
                if(c==''){
                    break;
                }
                System.out.print(c);
            }
            System.out.println();
        }
    
        public static void main(String[] args) {
            String str = "We are happy.";
            spaceReplace(str,100);//We%20are%20happy.
        }
    }

    举一反三:

    在合并两个数组时,如果从前往后复制每个元素,则需要重复移动元素多次,那么我们可以考虑从后往前复制,这样就能减少移动的次数

    拓展题:

    有两个排序的数组A1和A2,内存在A1的末尾有足够多的空余空间容纳A2,请实现一个函数,把A2中所有的数字插入A1,并且新数组是排好序的

    public class arrayMerge {
        public static void main(String[] args){
            int[] A1,A2;
            A1=new int[]{1,3,5,7,9};
    //        A1=new int[]{};
            A2=new int[]{2,2,3};
    //        A2=new int[]{2,4,6,8,10};
            arrayMerge(A1,A2,100);
        }
    
        public static void arrayMerge(int[] A1,int[] A2,int num){
            int[] res=new int[100];
            int len1=A1.length;
            int len2=A2.length;
            if(len1==0&&len2!=0){
                System.out.println(A2);
            }
            else if(len1!=0&&len2==0){
                System.out.println(A1);
            }
            else if(len1==0&&len2==0){
                new NullPointerException();
            }
            int mark1=len1-1,mark2=len2-1;
            int mark=len1+len2-1;
            while(mark1>=0&&mark2>=0){
                if(A1[mark1]>A2[mark2]){
                    res[mark--]=A1[mark1--];
                }
                else if(A1[mark1]<=A2[mark2]){
                    res[mark--]=A2[mark2--];
                }
            }
    //        System.out.print("a");
            while(mark1<0&&mark2>=0){
                res[mark--]=A2[mark2--];
            }
    //        System.out.print("b");
            while(mark1>=0&&mark2<0){
                res[mark--]=A1[mark1--];
            }
    //        System.out.print("c");
            for(int i=0;i<len1+len2;i++){
                System.out.print(res[i]+" ");
            }
        }
    }

  • 相关阅读:
    模板方法模式
    LINQ多条件OR模糊查询
    在LINQ中实现多条件联合主键LEFT JOIN
    js只显示整点
    Vue-cli2中处理跨域
    vue动态绑定类(实现tab)
    Vue中引入cdn同时防止cdn挂掉
    vue+nginx开启gzip压缩
    Vue路由守卫
    vue-router嵌套路由和二级目录(域名)
  • 原文地址:https://www.cnblogs.com/ak918xp/p/14421224.html
Copyright © 2011-2022 走看看