关于数组的总结(引用、常用方法、深浅拷贝、常见题型-双指针)

什么是数组?

数组本质上是能让我们 "批量"创建相同类型的变量

创建数组

public static void main(String[] args) {
	//方法一
	int[] array1 = {1,2,3};
	//方法二
	int[] array2 = new int[]{1,2,3};
	//方法三
	//如果不给数组赋值,那么默认是{0,0,0};
	int[] array3 = new int[3];
}

数组与引用

数组是引用类型,那么我们该如何理解这个小可爱呢?
假如我们在主函数中创建了一个数组:

public static void main(String[] args) {
	int[] array1 = {1,2,3};
}

那么在内存中的存储方式是这样的:
在这里插入图片描述
即array1存储的是数组在堆中的地址,array1称之为引用。

String 和 数组作为参数传值:(牛客常考题型)

public static void main(String[] args) {
	int[] array = {1,2,3};
	String str = "hello";
	method(array,str);
	System.out.println(Arrays.toString(array));
	System.out.println(str);
}

public static void method(int[] array,String str) {
	array[0] = 100;
	str = "world"; 
}

我以为的结果:

[10023]
world

实际结果:

[100,2,3]
hello

没有调用方法之前:
在这里插入图片描述

array 作为参数传递过去的是一个地址,method方法形式参数获得这个地址后,将数组0下标改为100;
str 作为参数传递过去的同样是一个地址,method方法形式参数获得这个地址后,将 str 指向了新的字符串"world",但是原来的str并没有改变!

数组常用的方法

  1. 将数组转为字符串:toString();(常用于打印数组)
public static void main(String[] args) {
	int[] array1 = {1,2,3};
	System.out.println(Arrays.toString(array1));
}

结果:

[1,2,3]

自己实现toString();方法:

    public static void method(int[] array) {
        System.out.print("[");
        for(int i = 0;i < array.length;i++) {
            if (i < array.length-1) {
                System.out.print(array[i] + ", ");
            }else {
                System.out.print(array[i] + "]");
            }
        }
    }
  1. 将二维数组转为字符串:deepToString();(常用于打印二维数组)
    public static void main(String[] args) {
        int[][] array = {{1,2,3},{4,5,6}};
        System.out.println(Arrays.deepToString(array));
    }

结果:

[[1, 2, 3], [4, 5, 6]]

自己实现deepToString();

    public static void method(int[][] array) {
        System.out.print("[");
        for (int i = 0; i < array.length; i++) {
            for (int j = 0; j < array[0].length; j++) {
                if (j == 0) {
                    System.out.print("[" + array[i][j] + ", ");
                }else if (j < array[0].length-1) {
                    System.out.print(array[i][j] + ", ");
                }else {
                    System.out.print(array[i][j] + "]");
                }
            }
            if (i < array.length-1) {
                System.out.print(", ");
            }
        }
        System.out.println("]");
    }
  1. 给数组排序 Arrays.sort();

关于排序,我写了一篇常见排序的博客,大家感兴趣的话可以去看看。
链接:几种常见的排序

上代码!

    public static void main(String[] args) {
        int[] array = {7,2,6,9,1,5};
        Arrays.sort(array);
        System.out.println(Arrays.toString(array));
    }

结果:

[1, 2, 5, 6, 7, 9]
  1. 数组的拷贝

关于数组拷贝,我写的一篇博客,关于深浅拷贝的区别(真的很清晰)
关于深浅拷贝

Java中数组常见的拷贝方式有四种:

第一种:Arrays.copyOf(需要拷贝的数组,需要拷贝的长度);
eg:

    public static void main(String[] args) {
        int[] array = {7,2,6,9,1,5};
        int[] copy = Arrays.copyOf(array,2);
        System.out.println(Arrays.toString(copy));
    }

结果:

[7, 2]

第二种:System.arraycopy(源数组,源数组的位置,目的数组,目的数组的位置,拷贝的长度);
eg:

    public static void main(String[] args) {
        int[] array = {7,2,6,9,1,5};
        int[] copy = new int[3];
        System.arraycopy(array,2,copy,0,3);
        System.out.println(Arrays.toString(copy));
    }

结果:

[6, 9, 1]

第三种:clone();
eg:

    public static void main(String[] args) {
        int[] array = {7,2,6,9,1,5};
        int[] copy = array.clone();
        System.out.println(Arrays.toString(copy));
    }

结果:

[7, 2, 6, 9, 1, 5]

第四种:for循环

    public static void main(String[] args) {
        int[] array = {7,2,6,9,1,5};
        int[] copy = new int[array.length];
        for (int i = 0; i < array.length; i++) {
            copy[i] = array[i];
        }
        System.out.println(Arrays.toString(copy));
    }

结果:

[7, 2, 6, 9, 1, 5]

数组常见的题型

array == null 和 array.length == 0 的区别:
在常见的题型中,我们经常会遇到需要判断数组是否为空或者数组的长度是否为0来避开一些边缘测试用例,防止数组越界。那么我们来看看它们的区别:

array == null 代表的意思是 array 这个引用没有地址,即它不指向任何内容。

    public static void main(String[] args) {
        int[] array = null;
        System.out.println(Arrays.toString(array));
    }

结果:

null

array.length == 0 代表的是 array 这个引用拥有地址,虽然它指向了一个地址,但是它指向的内容是啥也没有。

    public static void main(String[] args) {
        int[] array = new int[0];
        System.out.println(Arrays.toString(array));
    }

结果:

[]

如果你用 null 去做任何事情,都会出现空指针异常。

    public static void main(String[] args) {
        int[] array = null;
        int[] copy = array.clone();
        System.out.println(Arrays.toString(copy));
    }

在这里插入图片描述
所以在做题的时候,要判断清楚是array == null 还是 array.length == 0 或者两者都需要!

双指针
我们做数组题型常用的应该是双指针吧,很多题型都会用到双指针的思路。我们先来看看双指针入门题型:

逆置数组:把{1,2,3,4,5} 变为 {5,4,3,2,1};

思路:
在这里插入图片描述

    public static void main(String[] args) {
        int[] array = {1,2,3,4,5};
        System.out.println(Arrays.toString(array));
        method(array);
        System.out.println(Arrays.toString(array));
    }

    public static void method(int[] array) {
    	//加上判断
    	if (array == null || array.length == 0) {
    		return null;
    	} 
        int i = 0;
        int j = array.length-1;
        while (i < j) {
            int tmp = array[i];
            array[i] = array[j];
            array[j] = tmp;
            i++;
            j--;
        }
    }

结果:

[1, 2, 3, 4, 5]
[5, 4, 3, 2, 1]

进阶题型:
LeetCode: 删除数组中的重复项
传统思路是利用冒泡排序的思想,进行双重循环,遇到重复的将它置为数组中元素取值范围之外的值。像这个样子:

    public static void main(String[] args) {
        int[] array = {1,2,2,3,3};
        System.out.println(Arrays.toString(array));
        int[] res = method(array);
        System.out.println(Arrays.toString(res));
    }

    public static int[] method(int[] array) {
        //加上判断
    	if (array == null || array.length == 0) {
    		return null;
    	} 
        for (int i = 0; i < array.length; i++) {
            for (int j = i+1; j < array.length; j++) {
                if (array[i] == array[j]) {
                    array[j] = Integer.MAX_VALUE;
                }
            }
        }
        //将数组重新排序
        Arrays.sort(array);
        //遇到为Integer.MAX_VALUE 则停止循环
        int index = -1;
        for (int i = 0; i < array.length; i++) {
            if (array[i] == Integer.MAX_VALUE) {
                index = i;
                break;
            }
        }
        //然后拷贝数组
        int[] res = new int[index];
        for (int i = 0; i < index; i++) {
            res[i] = array[i];
        }
        return res;
    }

它的时间复杂度很高,如果遇到很多个元素那么可能会出现超时的情况。并且如果数组元素的取值范围是 int 的边界值,那么这种思路就不可以了。现在我们来利用正确的双指针:
在这里插入图片描述

    public static void main(String[] args) {
        int[] array = {1,2,2,3,3};
        System.out.println(Arrays.toString(array));
        int[] res = method(array);
        System.out.println(Arrays.toString(res));
    }

    public static int[] method(int[] array) {
        //加上判断
    	if (array == null || array.length == 0) {
    		return null;
    	} 
        int i = 0;
        int j = 1;
        while (j < array.length) {
            //如果 array[i] == array[j] j++;
            if (array[i] == array[j]) {
                j++;
            }else {
                i++;
                array[i] = array[j];
                j++;
            }
        }
        //此时 i 下标代表不重复的边界
        int[] res = new int[i+1];
        for (int k = 0; k < i+1; k++) {
            res[k] = array[k];
        }
        return res;
    }

结果:

[1, 2, 2, 3, 3]
[1, 2, 3]

这种方法不仅时间复杂度低,只需要遍历一遍数组即可。而且不会存在边界值问题。
还有一个常见的题型:

合并两个有序数组:{1,3,6,8} 和 {2,3,5} 变为 {1,2,3,3,5,6,8};

    public static void main(String[] args) {
        int[] array1 = {1,3,6,8};
        int[] array2 = {2,3,5};
        int[] res = method(array1,array2);
        System.out.println(Arrays.toString(res));
    }

    public static int[] method(int[] array1,int[] array2) {
        int i = 0;
        int j = 0;
        // k 指针操作 res 数组
        int k = 0;
        int[] res = new int[array1.length+array2.length];
        while (i < array1.length && j < array2.length) {
            // array1[i] < array2[j]
            if (array1[i] < array2[j]) {
                res[k++] = array1[i++];
            }else {
                res[k++] = array2[j++];
            }
        }
        // 当 array1 中还有元素时
        while (i < array1.length) {
            res[k++] = array1[i++];
        }
        //同理 当 array2 中还有元素时
        while (j < array2.length) {
            res[k++] = array2[j++];
        }
        return res;
    }

结果:

[1, 2, 3, 3, 5, 6, 8]

数组作为载体

常见的一些算法也是用数组作为载体来考察的。
比如
贪心算法:买股票的最佳时机
动态规划:打家劫舍
广度优先搜索(BFS):岛屿数量
深度优先搜索(DFS):岛屿周长

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值