仅有代码

一、数组中重复数组

/**
 * 数组中重复的数字
 * 在一个长度为 n 的数组里的所有数字都在 0 到 n-1 的范围内。
 * 数组中某些数字是重复的,但不知道有几个数字是重复的,也不知道每个数字重复几次。
 * 请找出数组中任意一个重复的数字。(或输出全部重复数字)
 * 例如:
 * Input:
 * {2, 3, 1, 0, 2, 5}
 * Output:
 * 2
 */
public class DuplicateArrayNum {

    public boolean duplicate(int nums[], int length) {
        if(nums == null | length <= 0) {
            return false;
        }
        for(int i=0; i<length; i++) {
            while(nums[i] != i) {
                if(nums[i] == nums[nums[i]]) {
                    System.out.println(nums[i] + ", ");
                    return true;
                }
                //2,3,1,0,2,1
				/*//换位
				int t = nums[i];
				System.out.println("1、t is : " + t + "    nums[i] is :" + nums[i]);

				System.out.print("2、 nums[nums[i]] is : " + nums[nums[i]]);
				nums[i] = nums[nums[i]];
				System.out.println("        nums[i] is :" + nums[i] );

				nums[nums[i]] = t;
				System.out.println("3、nums[i]" + nums[i] + "   nums[nums[i]] is: "+ nums[nums[i]] + "    t is:"+ t);*/
                /**
                 * 以上错误原因:
                 * 分析:第一步:  i=0   nums[0]=2     此时  t=2  nums[0]=2
                 * 第二步: i=0  nums[nums[0]]-> nums[2]=1
                 *        nums[0]=2
                 *        	赋值: nums[0] = (nums[nums[0]] = 1 )
                 *        即第二步之后:nums[0]=1
                 *第三步:    i=0  nums[nums[0]]->nums[1]=2
                 *     此时t赋值就发生了错误。
                 *
                 * 总结: 因为在第二步nums[0]的值发生了改变,因此在第三步nums[nums[i]]就指向了下标为1的数字,不符合我们期望(下标0和下标2发生数值交换)
                 *   因此发生错误!
                 */
                //若向避免错误,必须将下标赋值给提前定义好的变量
                int a = nums[i];
                int b = nums[nums[i]];
                //此时a、b表示的就是将要发生数值交换的数组的下标
                //进行数值交换
                int t = nums[a];
                nums[a] = nums[b];
                nums[b] = t;
                for(int c=0; c<nums.length; c++) {
                    System.out.print(nums[c] + " , ");
                }
                System.out.println();
            }
        }
        return false;
    }

    public boolean duplicate2(int[] nums, int length) {
        if (nums == null || length <= 0)
            return false;
        for (int i = 0; i < length; i++) {
            while (nums[i] != i) {
                if (nums[i] == nums[nums[i]]) {
                    System.out.println(nums[i] + ", ");
                    return true; //只能查出一个
                    //break;//使用break可以查询出这个数组中全部有重复的数字
                }
                swap(nums, i, nums[i]);
            }
        }
        return false;
    }

    private void swap(int[] nums, int i, int j) {
        nums[i] = nums[i] ^ nums[j];
        nums[j] = nums[i] ^ nums[j];
        nums[i] = nums[i] ^ nums[j];

        for(int a=0; a<nums.length; a++) {
            System.out.print(nums[a] + " , ");
        }
        System.out.println();
    }

    public static void main(String[] args) {
        int[] nums = {1,2,3,5,0,2};
        new DuplicateArrayNum().duplicate(nums, nums.length);
    }
}

二、二维数组的查找

/**
 * 二维数组中的查找
 * 作者:陶沅玱
 * 给定一个二维数组,其每一行从左到右递增排序,从上到下也是递增排序。给定一个数,判断这个数是否在该二维数组中。
 * Consider the following matrix:
 * [
 *   [1,   4,  7, 11, 15],
 *   [2,   5,  8, 12, 19],
 *   [3,   6,  9, 16, 22],
 *   [10, 13, 14, 17, 24],
 *   [18, 21, 23, 26, 30]
 * ]
 * Given target = 5, return true.
 * Given target = 20, return false.
 */
public class TwoArrayInFind {
    /**
     * 方法一
     * @param array: 二维数组
     * @param target: 要检索的数字
     * @return
     * 时间复杂度为O(n²), 空间复杂度为O(1)
     */
    public boolean find(int[][] array, int target) {
        if(array==null & array.length==0 & array[0].length==0) {
            return false;
        }
        for(int i=0; i<array.length; i++) {
            for(int j=0; j<array[0].length; j++) {
                if(target == array[i][j]) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 要求时间复杂度 O(M + N),空间复杂度 O(1)。其中 M 为行数,N 为 列数。
     * 该二维数组中的一个数,小于它的数一定在其左边,大于它的数一定在其下边。
     * 因此,从右上角开始查找,就可以根据 target 和当前元素的大小关系来缩小查找区间,
     * 当前元素的查找区间为左下角的所有元素。
     */
    public boolean find2(int[][] nums, int target){
        if(nums==null & nums.length==0 & nums[0].length==0){
            return false;
        }
        //从右上角开始查找, 因此定义变量获取二维数组的长度
        int rows = nums.length;
        int cols = nums[0].length;

        //右上角的坐标(也表示target的坐标)
        int a = 0;
        int b = nums[0].length-1;

        //每次都要从右上角开始遍历
        //因此结束条件为:行超过>nums.length, 列小于0
        while(a <= nums.length-1 && b>=0 ){
            System.out.println(nums[a][b]);
            //目标小于当前坐标值,往下走
            if(nums[a][b] < target){
                a++;
            }
            //目标大于当前坐标值,往左走
            else if(nums[a][b] > target){
                b--;
            }
            //否则,相同
            else {
                return true;
            }
        }
        return false;
    }

    public static void main(String[] args) {
        int[][] arr = new int[][] { { 1, 4, 7, 11, 15 }, { 2, 5, 8, 12, 19 }, { 3, 6, 9, 16, 22 },
                { 10, 13, 14, 17, 24 }, { 18, 21, 23, 26, 30 } };

        System.out.println(new TwoArrayInFind().find2(arr, 18));
    }

}

三、替换空格

/**
 * 将一个字符串中的空格替换成 "%20"。
 */
public class ReplaceBlank {

    //自己写的
    //因为替换空格的有肯能不是一个字符,因此字符串还需要‘扩容’,因此此处必须定义成StringBuffer类型的数组
    //a_b_c  此时_表示一个空格
    public String replaceStr(StringBuffer str){
        //使p1指向该字符串的最后一位下标
        int p1 = str.length()-1;
        //System.out.println("p1: " + p1);
        //此处for循环中不可以使用 i<str.length(), 因为str一有空格就会加两个空格,因此此处必须用 i<p1
        for(int i=0; i<p1; i++){
            //判断如果有空格,那么再添加两个空格字符
            if(str.charAt(i) == ' '){
                //System.out.println("发现空格是第几位:"+ i);
                str.append("  ");
            }
        }
        //此时变成了 a_b_c____

        //定义p2指向最新字符串的最后一位下标
        int p2 = str.length()-1;

        //解题思路:p1从最后一位往前一位,发现空格,把p1++所指向字符串的值给p2下标所指向字符串的值,
        //   然后 setCharAt(--p2, 0), setCharAt(--p2, 2), setCharAt(--p2, %),
        // 此时p2=p1,
        //因为此时p2下标指向的字符是 '%', 因此p2需要向前一位,即p2--
        //p1继续往前。。重复之前步骤
        //直到p1=0, 循环结束
        while(p1 >= 0) {
           //System.out.println(p1);
            if (str.charAt(p1) == ' ') {
                str.setCharAt(p2--, '0');
                str.setCharAt(p2--, '2');
                str.setCharAt(p2, '%');
                //此时p2=p1
                //System.out.println(str.toString())
                //因为此时p2下标指向的字符是 '%',因此p2需要向前一位,即p2--
                p2--;
            }
            //如果当前p1指向的位不是空格,那么需要把当前p1指向的字符直接给p2,然后p2--
            else{
                char c = str.charAt(p1);
                str.setCharAt(p2, c);
                p2--;
            }
            p1--;
        }
        return str.toString();
    }

    //标准答案
    //解题思路
    //在字符串尾部填充任意字符,使得字符串的长度等于替换之后的长度。因为一个空格要替换成三个字符(%20),
    //       因此当遍历到一个空格时,需要在尾部填充两个任意字符。
    //令 P1 指向字符串原来的末尾位置,P2 指向字符串现在的末尾位置。
    //       P1 和 P2 从后向前遍历,当 P1 遍历到一个空格时,就需要令 P2 指向的位置依次填充 02%(注意是逆序的),
    //       否则就填充上 P1 指向字符的值。
    //从后向前遍是为了在改变 P2 所指向的内容时,不会影响到 P1 遍历原来字符串的内容。
    public String replaceSpace(StringBuffer str) {
        int P1 = str.length() - 1;
        for (int i = 0; i <= P1; i++)
            if (str.charAt(i) == ' ')
                str.append("  ");

        int P2 = str.length() - 1;
        /**
         * while循环参数详解
         * p1>=0 证明遍历到头了
         * p2>p1 每一次添加完'%20'后,p2=p1
         */
        while (P1 >= 0) {
            //此处是判断当前p1前面的那个字符是不是空格
            //而我写的是判断当前p1这个字符是不是空格
            char c = str.charAt(P1--);
            if (c == ' ') {
                str.setCharAt(P2--, '0');
                str.setCharAt(P2--, '2');
                str.setCharAt(P2--, '%');
            } else {
                str.setCharAt(P2--, c);
            }
        }
        return str.toString();
    }

    public static void main(String[] args){
        System.out.println(new ReplaceBlank().replaceStr(new StringBuffer("a b c")));
    }
}