//
//版本1:有一个数组,其中只有一个数字出现1次,其余数字都出现了2次
//例如:1 2 3 4 5 1 2 3 4
//
//版本2:
//一个数组中只有两个数字是出现一次,其他所有数字都出现了两次。
//例如: 1 2 3 4 5 1 2 3 4 6
// //001
// //010
// //011
// //100
// //101 110
// //
// 编写一个函数找出这两个只出现一次的数字。
//
//分组:
//分组的要领,就是讲2个单身狗必须放在2个组,同时每个组剩余的数字都是成对出现的
//
//5^6
//101
//110
//011
//以第一位分割
//5 1 1 3 3
//6 2 2 4 4
//以第二位分割:为1的在一起,为0的在一起
//5 1 1 4 4
//6 2 2 3 3
运算符 | 描述 | 实例 |
& | 按位与操作,按二进制位进行"与"运算。运算规则: 0&0=0; 0&1=0; 1&0=0; 1&1=1; | (A & B) 将得到 12,即为 0000 1100 |
| | 按位或运算符,按二进制位进行"或"运算。运算规则: 0|0=0; 0|1=1; 1|0=1; 1|1=1; | (A | B) 将得到 61,即为 0011 1101 |
^ | 异或运算符,按二进制位进行"异或"运算。运算规则: 0^0=0; 0^1=1; 1^0=1; 1^1=0; | (A ^ B) 将得到 49,即为 0011 0001 |
~ | 取反运算符,按二进制位进行"取反"运算。运算规则: ~1=-2; ~0=-1; | (~A ) 将得到 -61,即为 1100 0011,一个有符号二进制数的补码形式。 |
<< | 二进制左移运算符。将一个运算对象的各二进制位全部左移若干位(左边的二进制位丢弃,右边补0)。 | A << 2 将得到 240,即为 1111 0000 |
>> | 二进制右移运算符。将一个数的各二进制位全部右移若干位,正数左补0,负数左补1,右边丢弃。 | A >> 2 将得到 15,即为 0000 1111 |
//n*n =100*100 =10000
//把所有数组异或在一起
//把两个单身狗异或在一起,但是不知道谁是单身狗,就把所有数字异或在一起,异或时相等的为0,七十九把不是单身狗的数字刨除了
void find_single_dog(int arr[], int sz, int single_dog[])
{
int ret = 0;
int i = 0;
for (i = 0; i < sz; i++)
{
ret ^= arr[i];
}
//计算ret的哪一位二进制位是1//ret32位,进行异或
int pos = 0;
for (i = 0; i < 32; i++)
{
if (((ret >> i) & 1) == 1)//都为1才为1
{
pos = i;
break;
}
}
for (i = 0; i < sz; i++)
{
if (((arr[i] >> pos) & 1) == 1)
{
single_dog[0] ^= arr[i];
}
else
{
single_dog[1] ^= arr[i];
}
}
}
int main()
{
int arr[] = { 1,2,3,4,8,1,2,3,4,6 };
int sz = sizeof(arr) / sizeof(arr[0]);
int single_dog[2] = {0};
find_single_dog(arr, sz, single_dog);
printf("%d %d\n", single_dog[0], single_dog[1]);
return 0;
}