题目介绍
1-1000这1000个数放在含有1001个元素的数组中,只有唯一的一个元素重复,其它均只出现一次。每个数组元素只能访问一次,设计一个算法,将它找出来;不用辅助空间,能否实现?
解题思路
1. 不使用辅助空间
不使用辅助空间,我们可以想到的是用异或 ( ^ ) 来解决问题。
异或的用法是:A0=A,AA=0。我们可以得到,当相同的数进行异或的时候,就会得到0。这个时候得到的数组的那个成对的数就会异或为0。但是如果,我们将这个数组与 1-1000的数进行异或,剩下的数就是唯一成对的那个数 。
如 ( A^ B^ B^ C… ) ^ ( A^ B^ C… ) 即 A^ A^ B^ B^ B^ C^ C… 这个结果得到的就是 B ,即就是我们要的结果,数组中唯一成对的那个数。
核心代码
int N = 1001;
int result = 0;
for (int i = 1; i <= N-1; i++) {
result = result^i;//result 从 1异或到1000
}
for (int i = 0; i < N; i++) {
result = result^arr[i];//result与数组中的所有元素进行异或
}
完整代码
为了使代码 main 函数代码看上去更简洁,我将 交换数组元素的值 和 输出数组 写成两个方法
public static void main(String[] args) {
int N = 1001;
int[] arr = new int[N];
for (int i = 0; i < arr.length; i++) {
arr[i] = i + 1;
}
//最后一个数,是随机数
arr[arr.length-1] = new Random().nextInt(N-1);
//取随机索引,将上一行代码生成的随机数,插入到arr数组中去
int index = new Random().nextInt(N);
swap(arr, index, arr.length-1); //交换数组元素的值
print(arr); //输出数组元素
int result = 0;
for (int i = 1; i <= N-1; i++) {
result = result^i;
}
for (int i = 0; i < N; i++) {
result = result^arr[i];
}
System.out.println("数组中唯一成对的那个数是"+result);
}
//交换数组元素的值
public static void swap(int[] arr, int i, int j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
//输出数组
public static void print(int[] arr) {
for (int i : arr) {
System.out.print(i+" ");
}
System.out.println("");
}
2. 开辟辅助空间
这种方法,也就是创建一个数组,我姑且把这个新数组命名为 helper,开辟辅助空间的原理就是记录 arr 数组出现过的数,即,arr 数组的元素值,为 helper 数组的索引,当出现一个 读取 arr 数组元素值的时候,就在 helper 数组的索引加 1 ,因为存在成对的数,所以当遍历完整个 arr 数组之后, helper 数组中索引是成对的那个数的元素值为2,输出 helper 数组中,元素为2的那个数组,就是我们要找的数组中出现成对的那个数。
也许上面的话,可能有点饶,看下面的核心代码也许你就理解了。
核心代码
int[] helper = new int[N];
for (int i = 1; i < N; i++) {
helper[arr[i]]++;
//arr[i]是一个1-1000数的范围
//helper数组给 arr数组出现的数进行计数,理解为arr每出现一个数,helper数组就以这个数为索引的值进行自增。
}
for (int i = 1; i < N; i++) {
if (helper[i]==2) {
System.out.println("重复的那个数是"+i);
}
}
感谢大家的阅读,如果对上述内容有什么疑问的话,欢迎各位留言。(学习算法的第一天打卡,脑阔疼。)
结了,如果是找出数组中落单的那个数,那就更简单了,直接对这个数组进行异或即可。