题目1:一个数组中,除了某一个只出现过一次的数字外,其余数字均出现过2次,找出这个只出现了一次的数字。
思路:分析题干,发现强调了数组中数字出现的次数为1和2,则可以想到异或运算,两个相同的数字异或结果为0,相同的数异或的结果为其本身,且异或运算存在交换律和结合律,即a^b^a=b, b^a^a=b。那么利用异或运算的这些性质即可求解本题:依次将数组的每个数进行异或运算,异或的结果即为所求。
题目2:一个数组中,除了某两个只出现过一次的数字外,其余数字均出现过2次,找出这两个只出现了一次的数字。
思路:基于题目1的思路来分析第二题。可以将数组分为2组,如果这两个特殊的数刚好出现在这两个数组中,那对这两个数组分别求异或即可。现在的问题是如何进行分组?一个思路是先对原数组求异或,则得到的结果为这两个特殊数字的异或值tmp,找到tmp中第一个为1的位n,说明这两个数第n位一个为1一个为0。 按照这个思路将所有数字分组:将第n位为1和为0的数字分为两组,此时这两个特殊的数字分别出现在这两个数组中,那么对这两个数组分别进行异或计算即可得到这两个数。
下面给出第2题的代码:
void FindNumsAppearOnce(vector<int> data,int* num1,int *num2) {
if(data.size() < 2)
return ;
int tmp = 0;
for(int i = 0; i < data.size(); i ++) //求出所有数字的异或结果存在tmp中
tmp ^= data[i];
int n = 0; //tmp第一个为1的位数
while(tmp != 0)
{
if(tmp & 1)
break;
n ++;
tmp = tmp >> 1;
}
*num1 = 0;
*num2 = 0;
for(int i = 0; i < data.size(); i ++)
{
if((data[i] >> n) & 1)
*num1 = *num1 ^ data[i]; //data中第n位为1的数据与num1异或计算
else
*num2 = *num2 ^ data[i];
}
}