面试题(五)替换空格

题目:实现一个函数,把字符串中的每个空格替换成“%20”。如输入“We are happy”,输出“We%20are%20happy”。

思路:
1. 可以从前到后扫描字符串,每遇到空格便将其后的元素往后移动两位,然后写入“%20”。这样会有元素被移动多次。算法的时间复杂度为O(n^2)。
2. 先扫描字符串得到字符串中空格的数量,再从后往前扫描字符串:设置两个指针,一个指针newEnd指向替换后字符串的尾部,一个指针originalEnd指向原字符串尾部(此处用字符数组表示字符串,并且字符数组的空间足够大)。若originalEnd指向的元素非空格,则进行元素移动,否则进行替换。当两个指针重合时,替换结束。

代码(含单元测试):

public class Q5{

    public static void main(String[] args){
        Q5 q5 = new Q5();

        q5.test1();
        q5.test2();
        q5.test3();
        q5.test4();
        q5.test5();
        q5.test6();
    }

    // length is the number of characters in the string  
    public void replaceBlank(char[] string, int length){

        if(string == null || length <= 0)
            return;

        int blankNum = 0;

        for(int i = 0; i < length; i++)
            if(string[i] == ' ')
                blankNum++;

        int originalEnd = length - 1;
        int newEnd = originalEnd + blankNum * 2;

        while(originalEnd >= 0 && originalEnd < newEnd){
            if(string[originalEnd] == ' ')
            {
                string[newEnd--] = '0';
                string[newEnd--] = '2';
                string[newEnd--] = '%';
            }
            else
                string[newEnd--] = string[originalEnd];

            originalEnd--;
        }

    }

    // mutilple blank
    public void test1(){

        char[] string = new char[50];
        string[0] = 'A';
        string[1] = ' ';
        string[2] = 'o';
        string[3] = 'h';
        string[4] = 'j';
        string[5] = ' ';
        string[6] = 'k';
        replaceBlank(string, 7);

        for(int i = 0; i < string.length; i++)
            System.out.printf("%c ", string[i]);
        System.out.println();
    }

    // consecutive blank in the head
    public void test2(){

        char[] string = new char[50];
        string[0] = ' ';
        string[1] = ' ';
        string[2] = 'o';
        string[3] = 'e';
        string[4] = 'r';
        string[5] = ' ';
        string[6] = 'r';
        string[7] = 'w';
        string[8] = 'j';
        string[9] = 'q';
        string[10] = 'e';
        replaceBlank(string, 11);

        for(int i = 0; i < string.length; i++)
            System.out.printf("%c ", string[i]);
        System.out.println();
    }

    // consecutive blank in the tail
    public void test3(){

        char[] string = new char[50];
        string[0] = 'y';
        string[1] = ' ';
        string[2] = 's';
        string[3] = 'e';
        string[4] = 'i';
        string[5] = ' ';
        string[6] = ' ';
        replaceBlank(string, 7);

        for(int i = 0; i < string.length; i++)
            System.out.printf("%c ", string[i]);
        System.out.println();
    }

    //no blank
    public void test4(){

        char[] string = new char[50];
        string[0] = 'y';
        string[1] = 'd';
        string[2] = 'd';
        string[3] = 'e';
        string[4] = 's';
        string[5] = 'j';
        string[6] = 'r';
        replaceBlank(string, 7);

        for(int i = 0; i < string.length; i++)
            System.out.printf("%c ", string[i]);
        System.out.println();
    }

    // null 
    public void test5(){

        replaceBlank(null, 0);

        /*for(int i = 0; i < string.length; i++)
            System.out.printf("%c ", string[i]);
        System.out.println();*/
    }

    // just one blank
    public void test6(){

        char[] string = new char[50];
        string[0] = ' ';

        replaceBlank(string, 1);


        for(int i = 0; i < string.length; i++)
            System.out.printf("%c ", string[i]);
        System.out.println();

    }


}

性能:
由于字符串中所有字符(或许没有所有)只会移动一次,因此算法的时间复杂度为O(n),空间复杂度为O(1)。

类似题目:有两个有序的数组A1和A2,内存在A1的末尾有足够的空余空间容纳A2。实现一个函数,把A2中所有数字插入A1中,并且所有的数字是有序的。

思路:此时同样可以知道合并后数组的结束位置,建立指针newEnd指向结束位置,从后往前扫描A1和A2,比较后将较大的元素移动到newEnd处。

代码(含测试用例):

public class Q5plus{

    public static void main(String[] args){

        Q5plus p = new Q5plus();
        p.test1();
        p.test2();
        p.test3();
    }

    // length1 is the the number of elements in the nums1
    public void merge(int[] nums1, int[] nums2, int length1){

        //robust
        if(nums1 == null || nums2 == null || length1 <= 0)
            System.out.println("null array");


        int len2 = nums2.length;

        // newEnd point to the end of the new merged sequence
        int newEnd = length1 + len2 - 1;

        int index1 = length1 - 1;
        int index2 = len2 - 1;

        while(index1 >= 0 && index2 >= 0){
            if(nums1[index1] == nums2[index2]){
                nums1[newEnd--] = nums1[index1--];
                nums1[newEnd--] = nums2[index2--]; 
            }
            else if(nums1[index1] < nums2[index2]){
                nums1[newEnd--] = nums2[index2--];
            }
            else
                nums1[newEnd--] = nums1[index1--];
        }

        if(index2 >= 0)
            while(index2 >= 0)
                nums1[newEnd--] = nums2[index2--]; 
    }

    // no duplicate and index2 first decrease to 0
    public void test1(){
        int[] nums1 = new int[50];

        for(int i = 0; i < 20; i++)
            nums1[i] = i;

        int[] nums2 = new int[10];
        for(int i = 0; i < 10; i++)
            nums2[i] = i + 20;

        merge(nums1, nums2, 20);
        for(int i = 0; i < nums1.length; i++)
            System.out.printf("%d ", nums1[i]);
        System.out.println();
    }

    // has duplicate
    public void test2(){
        int[] nums1 = new int[50];

        for(int i = 0; i < 20; i++)
            nums1[i] = i;

        int[] nums2 = new int[10];
        for(int i = 0; i < 10; i++)
            nums2[i] = i + 2;

        merge(nums1, nums2, 20);
        for(int i = 0; i < nums1.length; i++)
            System.out.printf("%d ", nums1[i]);
        System.out.println();
    }

    // index1 first decrease to 0
    public void test3(){
        int[] nums1 = new int[50];

        for(int i = 0; i < 10; i++)
            nums1[i] = i + 10;

        int[] nums2 = new int[10];
        for(int i = 0; i < 10; i++)
            nums2[i] = i;

        merge(nums1, nums2, 10);
        for(int i = 0; i < nums1.length; i++)
            System.out.printf("%d ", nums1[i]);
        System.out.println();
    }

}

性能:
时间复杂度O(n),空间复杂度O(1)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值