import java.util.HashMap;
import java.util.Map;
/**
* 数组中只出现一次的数字
*
* 一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。
*/
public class JZ040FindNumsAppearOnce {
/**
* 异或
* 运算律: x 异或 x = 0 , x 异或 0 = x
* 交换律: x 异或 y 异或 z = x 异或 z 异或 y
*
* 1、初始化一个 temp=0,与数组中的所有数字异或,其结果一定是 x,y异或的结果。
* (因为其他的数都是出现两次,并且异或满足交换律,两两抵消得0,且异或0是不变的)。
* 2、找到 temp二进制中第一次出现 1的位置 idx作为标准分割数组为两个子数组 1,2。
* 那么 x,y就会被分别分到不同的子数组 1,2中。(因为 x,y的二进制第 idx位一定是一个为 1,一个为 0)
* 3、则*子数组 1中元素全部异或得到 x,子数组 2中元素全部异或得到 y。
* @param array
* @param num1
* @param num2
*/
public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) {
if (array == null || array.length <= 1) {
return;
}
int tmp = 0;
for (int a : array) {
tmp ^= a;
}
int idx = getIdx(tmp);
for (int a : array) {
if (isBitIndex(a, idx)) {
num1[0] ^= a;
} else {
num2[0] ^= a;
}
}
}
private int getIdx(int tmp) {
int idx = 0;
while ((tmp & 1) == 0 && idx < 32) {
tmp >>= 1;
idx++;
}
return idx;
}
private boolean isBitIndex(int a, int idx) {
a >>= idx;
return (a & 1) == 1;
}
/**
* 采用Hashmap
* @param array
* @param num1
* @param num2
*/
public void FindNumsAppearOnce2(int [] array,int num1[] , int num2[]) {
if (array == null || array.length <= 1) {
return;
}
Map<Integer, Integer> map = new HashMap<>();
for (int a : array) {
if (!map.containsKey(a)) {
map.put(a, 1);
} else {
map.put(a, map.get(a) + 1);
}
}
int count = 0;
for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
if (entry.getValue() == 1) {
if (count == 0) {
num1[0] = entry.getKey();
count++;
} else {
num2[0] = entry.getKey();
}
}
}
}
}