一 思想精髓
单身狗问题的关键就是或用^的性质:
亦或操作:二进制位置相同取0,相异取1
①0^a=a;
②a^a=0;
③a^1 那么a的所有位置按位取反
那么->一个数字被另外一个数字亦或两次等于它本身(相当于没有^,^运算满足交换律)
二 问题描述
①一条单身狗 :
一个数组中只有1个数字是出现一次,其它所有数字都出现了两次
编写一个函数找出这两个只出现一次的数字
刚开始定义的临时变量是0的原因: 0^任何数字都是它本身-》方便找出单身狗
将所有的数字进行^操作,那么最后就可以找出单身狗。
举例:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
int arr[] = { 1,1,3,3,5,5,8 };
int i = 0;
int len = sizeof(arr) / sizeof(arr[0]);
int ret = 0;
for (i = 0; i < len; i++)
{
ret = ret ^ arr[i];
}
printf("单身狗是%d", ret);
return 0;
}
②两条单身狗
一个数组中有2个数字是出现一次,其它所有数字都出现了两次
编写一个函数找出这两个只出现一次的数字
解题思路:这个问题稍微复杂一点。但是核心的思想仍然是利用好^。将两只单身狗的问题转化成一只单身狗的问题进行解决。
由于这个数组中存在两个单身狗,因此我们需要对单身狗进行分组,将不同的单身狗分在一组。其他剩下的元素两两配对。
因此可以对二进制位从低位向高位进行选择,如果是1的话,那么说明一个单身狗的这个位置是1,另一个单身狗的这个位置是0,是不同的,就可以将他们分开了。而对于相同的数字,这个位置肯定也是相同的。
1.先对原来的数组进行^,那么结果就是两个单身狗^的结果。
2.找出不同的位置进行分组。
3.分别在不同的组里找出单身狗
举例:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
int arr[] = { 1,1,3,3,4,5 };
int i = 0;
int len = sizeof(arr) / sizeof(arr[0]);
int n = 0;
int ret = 0;//用来存放不同的一位
int dog1 = 0;
int dog2 = 0;
for (i = 0; i < len; i++)
{
n ^= arr[i];//两只单身狗亦或的结果
}
for (i = 0; i < 32; i++)
{
if ((n >> i)%2 == 1)//注意运算符优先级的问题,%2那么只能是0或者1
{
ret = i;//记录出分组的1的位置,若两个位置亦或的结果是1,那么两个数不同,一个是0,一个是1,作为分组的依据
break;
}
}
for (i = 0; i < len; i++)
{
if ((arr[i] >> ret) % 2 == 1)//如果数组中这一位数组是1
{
dog1 ^= arr[i];
}
else
{
dog2 ^= arr[i];
}
}
printf("单身狗是:%d和%d", dog1, dog2);
return 0;
}
三 总结
运算符的运用特别的灵活,因此平时应该多做多看多练习,加深对运算符的理解!