思路:首先将数组遍历,把所有数组成员依次异或一遍。我们知道,异或操作符操作的是二进制位,相同为0,相异为1,所以两个相同的数异或之后结果为0。所以所有元素遍历异或后,得到的其实是两个“单身狗”异或操作之后的结果。然后,我们找到这个结果在第几位是为1(两个“单身狗”在第几个二进制位产生了不同)并把这个位数保存下来。之后再遍历一次数组,并且把这些数字依次右移,右移长度为之前保存的位数,再将结果与1进行按位与操作。由于相同的数字得到的结果肯定相同,并且两个“单身狗”在这一位是不同的,所以肯定能保证两个“单身狗”被分到不同的组内,并且除他们之外他们两个组内的成员一定是两两相同的。再将两个组内成员依次异或,便可以得到最终结果。
#include <stdio.h>
#include <string.h>
int main()
{
int arr[] = { 1,2,3,4,5,1,2,3,4,6 };
int z = sizeof(arr)/sizeof(arr[0]);
int k = 0;
int m = 0;
int num1 = 0;
int num2 = 0;
/*将num1与num2初始化为0,因为0与任何数异或的结果都是这个数自己,方
便下面分组后找到这两个单身狗*/
for(int i = 0; i < z; i++)
{
m = m ^ arr[i];//依次异或以得到两个单身狗异或的结果
}
for (int i = 0; i < 32; i++)
{
if (((m >> i) & 1 )== 1)/*与1进行按位与,如果最低位为1结果为
1,最低位为0结果为0,当为1时,说明两个单身狗在这位产生了不同*/
{
k = i;
break;
//找到两个单身狗在第几位产生了不同
}
}
for (int i = 0; i < z; i++)
{
if (((arr[i] >> k) & 1) == 1)/*此举意为将两个单身狗分开,因为
两个单身狗在这一位肯定不同,因此他们按位与1的结果肯定不同*/
{
num1 ^= arr[i];
/*如果被分到了这一组,直接用num1异或这个数,因为num1的初始
值为0,所以第一个数进来之后就是他自己,之后便依次异或被分到
这一组的数字即可,最终得到的就是单身狗其一,下面同理。*/
}
else
{
num2 ^= arr[i];
}
}
printf("%d %d", num1, num2);
return 0;
}