1.什么是数组里的单身狗
假定有这么一个数组,数组里的整数都成双成对,却有两个数字是单身数。
例如:int arr[10]={1,2,3,4,5,1,2,3,4,6};中的5和6便是单身数,该怎么找到它们?
2.^异或是什么?
按位异或的概念是指,对两个整数的二进制进行比较,若对应位数相同则为0,相异则为1。
例如:3的二进制为000....0011,而5的二进制为000....0101;则3^5的二进制为000....0110,值为6。
3.为什么说异或可以揪出单身狗?
如果用成对的情侣数,例如两个5对ret=0进行异或,(0101)^(0000)=(0101)---->(0101)^(0101)=(0000);
可见,对ret进行两次同一数值的异或,会使ret的值回到原值,而如果中间穿插一个单身数6:
(0101)^(0000)=(0101)---->(0101)^(0110)=(0011)---->(0011)^(0101)=(0110)=6;
最后ret的结果就为6这个单身数。
4.具体该怎么实现?
1.首先让所有整数与ret异或一遍,求出两个单身数的异或融合;
2.求两个单身数在第i个二进制位上是相异的,通过这个i,可以将两个单身数分开;
3.将第i位为1的数字分开出来与0逐个异或,就可以求出第一个单身数;
4.由于ret是两个单身数的异或融合,很容易通过第一个单身数求出第二个单身数。
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
int arr[] = { 1,2,3,4,5,1,2,3,4,6 };
int sz = sizeof(arr) / sizeof(arr[0]);
int ret = 0, i, j, single1 = 0, single2 = 0;
for (i = 0; i < sz; i++)
//将所有数字都与ret逐一异或,如果为两个相同的数,那么和ret产生的异或效果将会抵消
{
ret ^= arr[i];//最后ret的值将是两个单身数的异或结果
}
for (i = 0; i < 32; i++)
{
if (((ret >> i) & 1) == 1)//再求出ret的最后的为1的位数,该位为1说明两个单身数的二进制码在此位相异
break;
}
for (j = 0; j < sz; j++)
{
if (((arr[j] >> i) & 1) == 1)//通过位操作符和按位与操作符,可以将数组中此位为1的数筛选出来
{
single1 ^= arr[j];//此时进入到这里的数为成对的非单身数和其中一个单身数,经过相同逻辑的遍历异或,就可以求出single1
}
}
single2 = ret ^ single1;//再将single1与ret异或,取出single2
printf("%d %d\n", single1, single2);
return 0;
}