问题:1-1000放在含有1001个元素的数组中,只有唯一的一个元素值重复,其它均只出现一次。每个数组元素只能访问一次,设计一个算法,将它找出来;不用辅助存储空间,能否设计一个算法实现?
解法一:显然已经有人提出了一个比较精彩的解法,将所有数加起来,减去1+2+…+1000的和。这个算法已经足够完美了,相信出题者的标准答案也就是这个算法,唯一的问题是,如果数列过大,则可能会导致溢出。
解法二:异或就没有这个问题,并且性能更好。将所有的数全部异或,得到的结果与123…1000的结果进行异或,得到的结果就是重复数。
public class 唯一成对的数 {
public static void main(String[] args){
int N = 11;
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;
//随机下标
int index = new Random().nextInt(N);
Util.swap(arr,index,arr.length-1);
Util.print(arr);
int x1 = 0;
//对于任何数x,都有x^x=0,x^0=x,同自己求异或为0,同0求异或为自己
for(int i=1;i<= N-1; i++){
x1 = (x1^i);
}
for(int i = 0; i < N;i++){
x1 = x1^arr[i];
}
System.out.println();
System.out.println(x1);
System.out.println("============有辅助空间");
(2)
int[] helper = new int[N];
for (int i = 0; i < N; i++){
helper[arr[i]]++;
}
for (int i = 0; i < N; i++){
if(helper[i]==2){
System.out.println(i);
break;
}
}
}
}
异或的作用:
- 判断奇偶性
- 获取二进制位是1还是0(两种解决方案)
- 交换两个整数变量的值
- 不用判断语句,求整数的绝对值
(1)判断奇偶性
//这个实际考的不多, 太简单
//思路:奇数的二进制最低为一定为1,偶数的二进制最低位一定为0,
a^1==1?偶数:奇数
(2)获取二进制位是1还是0
当两个数的二进制表示,进行异或运算时,当前位的二进制表示不同则为1,相同则为0。
即:
0 ^ 0 = 0;
1 ^ 0 = 1;
0 ^ 1 = 1;
1 ^ 1 = 0;
按位异或的3个特点:
(1)0异或任何数 = 任何数;
(2)1异或任何数 = 任何数取反;
(3)任何数异或自己 = 把自己置0;
按位异或的几个常见用途:
(1)使某些特定的位翻转
例如对数10100001 的第2位和第3位翻转,则可以将该数与00000110进行按位异或运算。
10100001 ^ 00000110 = 10100111
(2) 实现两个值的交换,而不必使用临时变量。
例如交换两个整数a = 10100001, b = 00000110的值, 可通过下列语句实现:
a = a ^ b; //a = 10100111
b = b ^ a; //b = 10100001
a = a ^ b; //a = 00000110
即等效于以下两步:
① 执行前两个赋值语句:“a=a∧b;”和“b=b∧a;”相当于b=b∧(a∧b)。而b∧a∧b等于a∧b∧b(异或满足交换律,结合律)。b∧b的结果为0,因为同一个数与本身相∧,结果必为0。因此b的值等于a∧0,即a,其值为3。
② 再执行第三个赋值语句:a=a∧b。由于a的值等于(a∧b),b的值等于(b∧a∧b),因此,相当于a=a∧b∧b∧a∧b,即a的值等于a∧a∧b∧b∧b,等于b。
a得到b原来的值
(3)交换两个整数变量的值
//交换a、b的值
a=a^b
b=a^b
a=a^b
1.借助第三个变量来实现
C=A;A=B;B=C;
2.利用加减法实现两个变量的交换
A=A+B;B=A-B;A=A-B;
3.用位异或运算来实现,也是效率最高的
原理:一个数异或本身等于0 ;异或运算符合交换律
A=A^B;B=A^B;A=A^B
(4)不用判断语句,求整数的绝对值