一、题目
将1-1000这1000个数放在含有1001个元素的数组中,只有唯一的一个元素值重复,其它均只出现一次。每个数组元素只能访问一次,设计一个算法,将它找出来。
二、补充知识
random(100)//生成[0,100)的随机数
random.nextInt(30)//生成[0.30)的随机数
异或(^):相同则为0,不同则为1;
1、0 ^ A = A;(A为任何数)
2、异或可以消除重复,A ^ A = 0;
1、不采用辅助空间解法
>>解题思路
目前题目要求:每一个数组元素只能访问一次;不采用辅助空间
思路为“异或可以消除重复”,即A ^ A = 0,那么A ^ A ^ A = A,就可以找出重复的数A.
如:将1-4这4个数放在含有5个元素数组
arr[5] = { 1, 2, 3, 4, 2};
1 ^ 2 ^ 3 ^ 4 ^ 2 ^ 1 ^ 2 ^ 3 ^ 4 = 2
>>主要代码(完整代码在文章末尾)
//不采用辅助空间,位运算找到重复的数
int x = 0;
for(int i = 1; i <= N-1; i ++){
x = (x ^ i); //构造1 - (N-1)的^
}
for(int i = 0; i < N; i ++){
x = x ^ arr[i]; //使数组中每一个数与构造的 (1 - (N-1))进行^
}
System.out.print("\n不采用辅助空间重复数字为:" + x);
2、采用辅助空间解法
>>解题思路
1、新开一个辅助数组arr2
2、由于数组arr中的数只有一个是重复的,并且是从1 - (N-1)连续的,那么可以将这些连续的数作为arr2的下标,让该下标数组元素值 ++(初始值都为0)
如此,必有一个数组元素值为2,因为重复++了2次
3、再循环遍历arr2,判断哪个元素为2,输出该下标,即为重复的数。
>>主要代码(完整代码在文章末尾)
//采用辅助空间
int[] arr2 = new int[N];
for(int i = 0; i < N; i ++){
arr2[arr[i]] ++;
}
for(int i = 0; i < N; i ++){
if(arr2[i] == 2){
System.out.print("\n采用辅助空间重复数字为:" + i);
break;
}
}
三、完整代码
package lanqiao;
import java.util.Arrays;
import java.util.Random;
public class test01 {
public static void main(String[] args){
int N = 1001;
int[] arr = new int[N];
for(int i = 0; i < arr.length-1; i ++){
arr[i] = i+1; //填充数组数据
}
//最后一个数据从1 - (N-1)中随机填充(也就是指定重复的那一个数)
arr[arr.length-1] = new Random().nextInt(N-1) + 1;
//找到随机的数组下标
int index = new Random().nextInt(N-1);
//将重复值打乱到数组中
int temp = arr[index];
arr[index] = arr[arr.length-1];
arr[arr.length-1] = temp;
System.out.print(Arrays.toString(arr));
//不采用辅助空间,位运算找到重复的数
int x = 0;
for(int i = 1; i <= N-1; i ++){
x = (x ^ i); //构造1 - (N-1)的^
}
for(int i = 0; i < N; i ++){
x = x ^ arr[i]; //使数组中每一个数与构造的 (1 - (N-1))进行^
}
System.out.print("\n不采用辅助空间重复数字为:" + x);
System.out.print("\n———————————————————————————————————");
//采用辅助空间
int[] arr2 = new int[N];
for(int i = 0; i < N; i ++){
arr2[arr[i]] ++;
}
for(int i = 0; i < N; i ++){
if(arr2[i] == 2){
System.out.print("\n采用辅助空间重复数字为:" + i);
break;
}
}
}
}