1.题目描述
有这么一个整型数组,有两个数字只出现了一次,其他数字都只出现了一次,编写一个函数找出这两个不同的数字
2.思路讲解
假设数组中的数字为1,2,3,4,5,1,2,3,4,6
将5和6按位异或:5 ^ 6 ------> 101 ^ 110 = 0
按位异或的特性是相同为0,相反为1
也就是说5和6按位异或的结果是第1位和第2位不同,此时如果将数组中二进制数第1位为1的数字分一个组,第1位为0的数字分一个组
二进制第1位为1:1,3,5,1,3
二进制第1位为0:2,4,2,4,6
可以看到分为了2组,每个组中都只有1个数字出现了一次,其他数字都出现了2次,这个时候只要分别对2个组中的数字依次异或就可以得到那个只出现了一次的数字了
按照第2位不同来进行分组也是可以的,只不过要想找到第2位实现起来有些麻烦,所以就找从右到左最开始的那个不同位就可以了
所以思路可以分为以下几步:
第一步,将数组依次异或,相当于只让两个不同的数字进行按位异或,把这个值记为ret
第二步,找到ret中第几位是不同的,即第几位异或得到的二进制位是1,将那个位置记为pos
第三步,对数组中二进制位第pos位为1的数字进行分组,第pos位为0的数字进行分组,然后分别对两个组依次按位异或就能得到不同的那个数字了
3.代码实现
void find_two_single(int* arr, int sz)
{
//1.将数组所有元素依次按位异或
int i = 0;
int ret = 0;
for (i = 0; i < sz; i++)
{
ret ^= arr[i];//得到5和6进行异或后的值
}
//2.找到ret中第几位是1,将那个位置记为pos
int pos = 0;
for (i = 0; i < 32; i++)
{
if (((ret >> i) & 1) == 1)
{
pos = i;
break;
}
}
//3,分组按位异或
int single_1 = 0;
int single_2 = 0;
for (i = 0; i < sz; i++)
{
if ((arr[i] >> pos & 1) == 1)//把第pos位为1的数放到一个组中进行异或
{
single_1 ^= arr[i];
}
}
single_2 = ret ^ single_1;//ret是5和6异或的值,将ret再与其中1个异或,就能得到另一个数了
printf("%d %d", single_1, single_2);
}
int main()
{
int arr[] = { 0,1,2,3,4,5,0,1,2,3,4,6 };
int sz = sizeof(arr) / sizeof(arr[0]);
find_two_single(arr, sz);
return 0;
}
这种方法实现起来会比拿每一个数字去和其他数字依次进行比较来找出两个不同的数的方法要快