一、位运算前导知识
(一)异或^
- 定义:不同为1,可以理解为不进位的加法, 1+1=0, 0+0=0,1+0=1
- 性质:
- 交换律
- 结合律
- 对于任何数x,都有
x^x=0,x^0=x
- 自反性
A^B^B=A^0=A
,连续和同一个因子做异或运算,最终结果为自己
- 应用:
- 判断奇偶数
- 交换两个整数变量的值
- 获取二进制位是1还是0
- 不用判断语句,求整数的绝对值
二、找出唯一成对的数
- 题目:将1-1000的数字存放在含1001个元素的数组中,只有唯一的一个元素值重复,找出该数。不使用额外的辅助空间,且数组的每个元素只能访问一次。
- 思路:利用异或位运算的性质,偶数个相同的数做异或位0,奇数个相同的数做异或为该数本身,即
3^3=0, 3^3^3=3
。
1)假设重复的数为k且1<=k<=1000,得有1001个元素的数组为[1, 2, 3, ..., k, k, ..., 999, 1000]
2)构造异或的辅助数据,1^2^3^...^k^...^999^1000,从1到1000的异或
3)用数组与辅助数据做异或(1^2^3^...^k^k^...^999^1000)^(1^2^3^...^k^...^999^1000) = k
3.代码:
import java.util.Random;
public class 唯一成对的数 {
public static void main(String[] args) {
method1();
}
public static void swap(int[] arr, int i, int j){
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
public static void method1(){
int N = 1001;
int[] arr = new int[N];
//构造数据
for (int i = 0; i < arr.length -1; i++) {
arr[i] = i + 1;
}
arr[arr.length - 1] = (new Random().nextInt(N - 1)) + 1; //构造重复的数
System.out.println("重复元素: " + arr[arr.length-1]);
//随机存放重复元素
int index = new Random().nextInt(N);
swap(arr, index, arr.length -1);
//1.构造异或串(1^2^……^N-1)
int tmp = 0;
for(int i = 1; i <= N -1; i++){
tmp = (tmp ^ i);
//System.out.println((tmp ^ i));
}
//2.去除不重复的数据 arr ^ (1^2^……^N-1)
//元素个数为偶数则去除该元素,奇数则保留
for(int num : arr){
tmp = num ^ tmp;
}
System.out.println(tmp);
}
}