一看到这道题,我想到了之前学习过的异或。我们知道两个相同的数字异或的结果是 0,因为在计算机中,异或运算是按照二进制位来运算的,相同为 0 ,相异为 1 。任何数与 0 异或都等于它自己。既然我们要找出来一组数中不同的两个数字,也可以采用这种方法。
但是这次不是直接异或,而是要分组。将数组的数据分成两组,把这两个不一样的数分到两个组里,这样最后的异或结果就是这两个数了。那么具体怎么做呢?
第一步 所有数字异或
我们先将所有的数字异或一遍,结果存储在num中。
第二步 找num的二进制位中的1的位置
因为根据异或法则,相同为 0 ,相异为 1,那么如果两个数异或的结果num中二进制位中有1,就说明这两个数字不一样。这样问题就变成找num二进制位中的1,遍历32次就可以检查所有位。一旦找到一个位是1,我们便出循环不再查找,因为已经可以证明这两个数不一样了。接着我们可以将这个结果存储在pos中,以便分组。
第三步 按照pos位为0或者1分组
根据第二步,找到1就跳出来保存为pos,那么我们再来一个循环,判断所有数字异或后的结果,如果是1,分为一个组,否则,进入另一个组。
这样做,直到最后,所有的数字异或结束,相同的为 0,不同的则是这个数。具体代码如下:
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include<stdlib.h>
void find_diff_num(int *arr, int sz,int* px,int* py)
{
//1.所有数字异或
int num = 0;
int i = 0;
int pos = 0;
for (i = 0; i < sz; i++)
{
num ^= arr[i];
}
//2.找num的二进制位中的1的位置
for (i = 0; i < 32; i++)
{
if (((num >> i) & 1) == 1)
{
pos = i;
break;
}
}
//3.按照pos位为0或者1分组
for (i = 0; i < sz; i++)
{
if (((arr[i] >> pos) & 1) == 1)
{
*px ^= arr[i];
}
else
{
*py ^= arr[i];
}
}
}
int main()
{
int arr[] = { 1, 2, 3, 4, 5, 1, 2, 3, 4, 6 };
int sz = sizeof(arr) / sizeof(arr[0]);
int n1 = 0;
int n2 = 0;
find_diff_num(arr,sz,&n1,&n2);
printf("%d %d", n1, n2);
system("pause");
return 0;
}