异或 ^
相同为0,不同为1 同或则刚好相反
// 0101001 111001 111001
// 1001010 111001 000000
// 1100011 000000 111001
可以理解为无进制加法,即忽略进位的加法
异或操作满足分配律和结合律
实现两数交换可以使用异或
int a = 3. b = 4
a = a^b;
b = a^b;
a = a^b;
此时,a和b的值已经交换
例题:在一个数组中只有a出现了奇数次,其余数字都出现了偶数次,请找出这个a;
int [] arr = new int [n];
int eor = 0;
for(int i = 0 ; i < arr.length;i++){
eor ^=arr[i];
}
//此时eor就是a 因为奇数次异或等于本身,偶数次异或等于0
System.out.println(eor);
如果有一个不为0的数a,需要提取出其二进制中最右边的一个1
a &(~a + 1)
//000110010000
~a = 111001101111
~a +1 = 111001110000
a&(~a +1) 00000010000
如果一个数组中有a和b两个数字出现了奇数次 其余均出现了偶数次,需要找出a和b
首先跟一个奇数次一样定义eor = 0,循环异或数组中的所有元素,此时eor = a^b !=0;即eor中总有1位不为0,可用提取最右边1位1的方法找出这一位s,然后将数组分为两部分,一部分位s位位0,一部分为s位为1的,此时a和b一定在不同的两个部分,随机找一部分,定义eor' = 0,eor'循环与这一部分的所有数据异或得到的就是这个奇数次的数字a或b
则我们需要的就是 eor' 和eor^eor'
>> 右移 a >> 1 相当于a/2
<< 左移 a << 1 相当于a*2;
a*2 + 1 == (a<<2) | 1