题目描述
这里需要用到异或运算的性质:一个数字(不管是什么形式的数字,只要其二进制形式确定)和其自身的异或运算的结果一定位0。因此,如果一个数组中只有一个数字出现一次,其他数字都出现了两次,那么将整个数组中元素异或得到的结果就是那个只出现一次的数字。
本题要求出两个数字之外,其他的数字都出现了两次,找出这两个只出现一次的数字。怎么运用上面的思想呢?
1、将数组中元素相互异或的结果设为val,val依然不为0
2、怎么根据这个结果值val,将数组分为两个子数组,使得没有子数组中只有一个只出现一次的数字,其他数字都出现了两次?
val对应的二进制位中至少有一位为1,假设第n位为1。根据数组中元素的第n位是否为1,将数组元素分为两个子数组。这样两个相同的元素肯定被分配到同一个子数组中,并且每个子数组包含一个只出现了一次的数字,而其他的数字都出现了两次。运用上述方法,就可以分别求出这两个数字。
class Solution {
public:
void FindNumsAppearOnce(vector<int> data,int* num1,int *num2) {
//相同的数字异或的结果为0
if (data.size() == 0 || data.size() < 2 || num1 == NULL || NULL == num2){
return;
}
int val = 0;
for (size_t i = 0; i != data.size(); i++){
val = val ^ data[i];
}
//找出val的二进制形式从右到左第一个1出现的位置
int tmp = 0x1;
while ((val & tmp) == 0){
tmp = tmp << 1;
}
//分为两个子数组,求出这两个只出现了一次的数
*num1 = 0;
*num2 = 0;
for (size_t i = 0; i != data.size(); i++){
if ((data[i] & tmp) == 0){
*num1 = *num1 ^ data[i];
}
else {
*num2 = *num2 ^data[i];
}
}
return;
}
};