异或运算
相同为0,不同为1
- 异或运算的简便记法:无进位相加
异或运算的性质
- 异或运算满足交换律和结合律,即同一批数的异或结果是一样的
- 相同两数异或为0
异或运算的几个应用
- 不用额外变量交换两个数
// An highlighted block
int a = num1;
int b = num2;
a = a^b; // 此时a = num1^num2
b = a^b; // 此时b = num1^(num2^num2) = num1^0 = num1 = a
a = a^b; // 此时a = num1^num2^num1 = num2^0 = num2 = b
注意:这种交换操作只能交换处于不同内存空间的两个数,不能交换指向同一空间的两个数
- 一个数组中有一个数出现了奇数次,其他数都出现了偶数次,怎么找到这个数
方法: 令eor=0,然后 target = eor ^ arr[0] ^ arr[1] ^ … ^ arr[n-1]
原理如下:
int arr = [1,1,1,1,2,3,3,4,4,5,5]
// 则target为
int target;
int eor=0;
// 按照上述方法,target=(1^1^1^1)^2^(3^3)^(4^4)^(5^5)=0^2^0^0^0=2
// 这里的原理是异或运算的交换律和结合律,且偶数个相同数异或后为0,奇数个相同数异或后为其本身
- 提取int类型数最右侧的1
假设要提取N最右侧的1,则结果为:N&((~N)+1)
原理如下:
设 N=011011010000
则 ~N=100100101111
(~N)+1=100100110000
N&((~N)+1)=000000010000
- 一个数组中两种数出现奇数次,其余数出现偶数次,怎么找到这两个数。
原理如下:
public static void printOddTimesNum2(int[] arr){
int eor = 0;
for(int i =0; i < arr.length; i++){
eor ^= arr[i]
}
// eor = a^b
int rightOne = eor & ((~eor)+1); // 提取eor最右侧的1
int onlyOnne = 0;
for(int i =0; i < arr.length; i++){
if((arr[i] & rightOne) != 0){
//只异或最右侧为1的数
onlyOne ^= arr[i];
}
}
System.out.println(onlyOne + " " + (eor ^ onlyOne))
}