问题1:
数组中有一个数字出现奇数次,其余次数均出现偶数次,找到这个出现奇数次的数字
问题2:
数组中有两个数字出现奇数次,其余次数均出现偶数次,找到这个出现奇数次的数字
解题思路
利用 ^(异或:可以理解为无进位相加)的特性
a 0 0 0 0 1 1 0 0
b 1 1 0 0 1 0 1 0
a ^ b 1 1 0 0 0 1 1 0
特性 1)、
N ^ 0 = N
N ^ N = 0
特性 2)、
满足交换律或结合律
a ^ b ^ c = a ^ (b ^ c)、 a ^ b = b ^ a
特性 3) 、
异或顺序与结果无关(参考特性2)
代码实现:
public static void main(String[] args) {
// 数组中有一个数字出现奇数次,其余次数均出现偶数次,找到这个出现奇数次的数字
int arrs[] = {2, 2, 2, 2, 3, 3, 3, 5, 5, 6, 6, 2, 2, 1, 1};
int eor = 0;
for (int arr : arrs) {
eor ^= arr;
}
System.out.println(eor);
}
public static void main(String[] args) {
// 数组中有两个数字出现奇数次,其余次数均出现偶数次,找到这个出现奇数次的数字
int arrs[] = {2,2,2,2,3,3,3,5,5,5,6,6,2,2,1,1};
int eor = 0;
for(int arr: arrs){
eor ^= arr;
}
// eor = a ^ b
System.out.println(eor);
// 获取a ^ b的最右为1的位置(将a、b区分在两个区间内,因为a与b的)
/**
* a = 00000011 = 3
* b = 00000101 = 5
* 从右侧开始找到不同数的位置,根据这个位置将数组arrs分为两个阵营,
* 找到数组中与该位置相同的数 进行异或操作,那么最后剩下的就是 a、b其中一个
* 将a、b 与 eor 继续异或就可以获得另一个数据
*/
int right = eor & (~eor + 1);
System.out.println(right);
int a = 0;
for(int arr: arrs){
if((right & arr) == 0){
// if((right & arr) > 0){
a ^= arr;
}
}
System.out.println("a: " + a);
System.out.println("b: " + (eor ^ a));
}
延伸
两个数值型数据交换位置(经常用于数组中数据交换,但是注意数组中的 i、j不能相同(内存地址指向不同),否则会变成0)
public static void main(String[] args) {
int s1 = 10;
int s2 = 20;
s1 = s1 ^ s2;
s2 = s1 ^ s2; // s1 ^ s2 ^ s2 - > s1
s1 = s1 ^ s2; // s1 ^ s2 ^ s1 - > s2
System.out.println("s1: " + s1);
System.out.println("s2: " + s2);
}