当一个数组只有一个数出现奇数次,其他数都出现偶数次,如何找出这个数?
public static void main(String[] args) {
int []nums = {1,1,1,2,2,7,7,7,9,9,4,4,5,5};
int eor = 0;
for(int i:nums){
eor = eor^i ;
}
System.out.println(eor);
}
0^a = a ---- a^a = 0 异或也满足交换律和结合律
a= a^b
b=b^a
a = a^b
当a,b两个数在内存中不是同一个位置时,交换a,b的值
当一个数组有两个数出现奇数次,其他都是出现偶数次时,如何找出这两个数
public static void main(String[] args) {
int []nums = {1,1,1,2,2,7,7,7,9,9,4,4,5,5};
int eor = 0;
for(int i:nums){
eor = eor^i ;
}
int right = eor & (~eor+1); //提取最右侧的1
int only = 0;
for(int i : nums){
if((i & right) ==0)
only = only ^ i;
}
System.out.println(only +" "+(eor^only));
}
right = eor & (~eor+1) 这是最常用的 提取一位数二进制里的第一个1
因为 eor = 1111 0101
~eor = 0000 1010
~eor+1 = 0000 1011
eor &(~eor+1) = 0000 0001 提取出了eor 二进制最右侧的1
第一次异或时 eor = x ^ y ---- x和y 代表 数组中的两个出现奇数次的数
eor不为0 说明这两个数的二进制位中,最少有一位不为0 如果都为0,eor=0
代码中的right变量就是保存eor中的第一位1。(我们假设第二位是1),原数组中的所有数现在分为:第二位为1的数和第二位不为1的数。
x和y中必定是一个数第二位为1,一个数第二位不为1,因为根据异或原则,相同为0不同为1,既然x和y异或后有1,那么肯定他们两个数第二位不同。
用right变量(保存着第一位1)和数组中的数进行与运算,如果等于0(或者不等于0),就用only变量进行异或操作,因为只有两个数出现奇数次 而且这两个数第二位不相同(开始时我们假设第二位不同),那么最后only必然等于其中一个数
输出only 和 eor^only即可得到两个数
~ 非操作 即把一个数二进制都取反
4 = 0000 0100
~4 = 1111 1011
此时,因为计算机中都是用补码表示数字的 那么~4的补码就是 1000 0101 = -5