位运算
成对出现的数
最近在学习数据结构与算法,对算法题真的是又爱又恨,有些觉得挺有趣的,有时抓破头都想不出,这道题算是基础的入门题,我也才刚刚开始学,所以记录一下。
题目:寻找数组中唯一成对出现的数
要求:1-1000这1000个数放在含有1001个元素的数组中,只有唯一的一个元素值重复,其它均只出现一次。每个数组元素只能访问次,设计一个算法,将它找出来;不用辅助存储空间,能否设计一个算法实现?
/**
* @author Zhang
* @date 2022/3/3 16:16
* @description 唯一成对的数
*/
public class 唯一成对的数 {
public static void main(String[] args) {
/*
* 首先我们先来创建一个满足要求的数组
* 1000个数组,调试起来,不太方便,因此,我们以20个数来举例子
* 倘若无误,只需将N的值换为1001即可
*/
int N = 21;
int[] arr = new int[N];
for (int i = 0; i < arr.length; i++) {
arr[i] = i + 1;
}
//随机放入一个1 ~ N-1的数
arr[arr.length - 1] = new Random().nextInt(N - 1) + 1;
//随机下标
int index = new Random().nextInt(N);
//交换arr.length - 1 和 index 两个索引下标的值
Util.swap(arr, index, arr.length - 1);
System.out.println(Arrays.toString(arr));
//至此,我们已经构建出一个满足题目要求的数组,接下来我们来看看,如何解题
}
}
1.1、解法1:辅助空间
辅助空间法(注:不符合题目要求,仅供学习)
方法描述:
1、另外开辟一个容量为1001的数组tempArr
2、遍历目标数组,将目标数组的元素出现时,tempArr数组对应下标的的元素值+1,即tempArr[arr[i]]++
3、再次遍历tempArr数组,输出元素值为2的元素
public class 唯一成对的数 {
public static void main(String[] args) {
//构建题设数组……
//解法1:辅助
//题目说不能使用空间,故不能使用此方法,但是我们可以用来学习比较
//创建一个数组,假设为B,利用数组B的下标来存放原数组元素出现的次数
int[] tempArr = new int[N];
for (int i = 0; i < arr.length; i++) {
tempArr[arr[i]]++;
}
for (int i = 0; i < tempArr.length; i++) {
if (tempArr[i] == 2) {
System.out.println("重复的数:" + i);
break;
}
}
}
}
1.2、解法2:异或
首先我们先来简单了解一下位运算中“异或”运算。
异或:可以理解为不进位加法,1^1=0, 0^0=0, 1^0=1
性质:
1、结合律,可以交换运算因子的位置,结果不变
2、结合律,即(a^b)^c = a^(b^c)
3、对于任何数x,都有x^x = 0, x^0 = x。即,同自己求异或为0,同0求异或为自己
4、自反性,A^B^B = A^0 = A
public class 唯一成对的数 {
public static void main(String[] args) {
//构建题设数组……
//解法2:异或,利用 A^0=A, A^A=0, A^B^B^C^C = A^0^0 = A
//因此“异或”运算,在求 重复数字 或者 去除重复数字 的题目中有奇效
//算法:(1^2^...^k^...^k^...^N) ^ (1^2^...^k^...^N)
//1、先计算N个数的异或(后面部分)
for (int i = 1; i < N; i++) {
xi = (xi ^ i);
}
//2、再计算数组的元素的异或(前面部分)
for (int i = 0; i < arr.length; i++) {
xi = (xi ^ arr[i]);
}
System.out.println("重复的数:" + xi);
}
}
运行结果:
如有错误,敬请指正!!!