题目
一个整形数组里除了两个数字之外,其它的数字都出现了两次。找到这两个只出现一次的数字。
思路
异或运算的一个性质: 任何一个数字异或它自己都等于0。
也就是说,如果我们从头到尾依次异或数组中的每一个数字,那么最终的结果刚好是那个只出现一次的数字,因为那些成对出现两次的数字全部在异或中抵消了。
代码
#include <iostream>
using namespace std;
// 寻找num二进制表达式中1最先出现的位置
unsigned FindFirstBitIs1(int num)
{
int indexBit = 0;
while ( num > 0 && indexBit < 32)
{
num >>= 1;
++indexBit;
}
return indexBit;
}
// 判断第n位是否为1
bool theNthBitIs1(int num, unsigned n)
{
num >>= n;
return num & 1;
}
// 找出数组中只出现一次的两个数。(其它数字都出现两次)
// num1与num2表式函数的两个返回值
void FindNumsAppearOnce(int data[], int length, int* num1, int* num2)
{
if (data == nullptr || length < 2)
return;
// 将整个数组进行异或运算,结果保存在result中。
int result = 0;
for (int i = 0; i < length; ++i)
result ^= data[i];
// 找到result二进制表达中首个'1'的位置
unsigned indexOf1 = FindFirstBitIs1(result);
// 可以依据indexOf1位置是否为1将数组分成两个子数组,并且每个字数组中只会有1个特殊的数字只出现一次。
// 其它的数会“成对”出现在两个不可用的数组中。
*num1 = *num2 = 0;
for (int j = 0; j < length; ++j)
{
if (theNthBitIs1(data[j], indexOf1 - 1))
*num1 ^= data[j]; // 通过异或找出只出现一次的数字num1
else
*num2 ^= data[j]; // 通过异或找出只出现一次的数字num2
}
}
int main()
{
int arr[] = {1,2,2,3,3,4,4,1,0,8};
int num1, num2;
FindNumsAppearOnce(arr, sizeof(arr) / sizeof(int), &num1, &num2);
cout << "The numbers that appear once is:"
<< num1 << "," << num2 << endl;
return 0;
}