一个单身狗
题目:一个数组中只有一个数字是出现一次,其他所有数字都出现了两次。
编写一个函数找出这个只出现一次的数字。
例如:
有数组的元素是:1,2,3,4,1,2,3,4,5
只有5只出现1次,要找出5。
在成对的数中找到一个单独的,首先我们要了解位操作符 ^ (异或),如果操作数二进制位相同则为0,相异则为1,那让我们想象一下,如果一个数和它自己异或,或者和0异或结果是多少呢?
由图我们不难看出,一个数和它自己异或的结果是0,如果和0异或的话结果是它本身。
a ^ a = 0;
a ^ 0 = a;
所以这道题我们可以使用异或来解决,成对的数异或结果自然会是0,最后只剩单身狗与0异或得到它本身。代码如下:
#include<stdio.h>
int main()
{
int arr[9] = { 1,2,3,4,1,2,3,4,5 };
int tmp = 0;
for (int i = 0; i < 9; i++)
{
tmp ^= arr[i];
}
printf("%d", tmp);
return 0;
}
两个单身狗
如果数组中只有一个单身狗是很好找出来的,但是如果数组中有两个单身狗呢?我们应该怎么找出来?显然简单的异或我们只能得到两个单身狗异或的结果,我们还是要将成对的数异或掉,再想办法把两个单身狗分开异或。
题目:一个数组中只有两个数字是出现一次,其他所有数字都出现了两次。
编写一个函数找出这两个只出现一次的数字。
例如:
有数组的元素是:1,2,3,4,5,1,2,3,4,6
只有5和6只出现1次,要找出5和6。
首先我们要将两个单身狗分开,两个单身狗异或的结果肯定不会是0,找到两个单身狗异或后为1的位数,这样我们就可以把两个单身狗分开,也可以将剩下成对的数分在一起,因为成对的数二进制的每个位数一定相同。
如图,第一步将所有数异或得到两位单身狗异或的结果,找到结果中为1是第几位,用这一位将两位单身狗分到不同的两个组,然后再让num1和num2分别异或就可以得到两个单身狗。代码如下:
#include<stdio.h>
int main()
{
int arr[10] = { 1,2,3,4,5,6,1,2,3,4 };
int num1=0;
int num2=0;
int tmp = 0;
for (int i = 0; i < 10; i++)
{
tmp ^= arr[i];//tmp就是两个单身狗异或的结果
}
int k = 0;
for (int j = 0; j < 32; j++)
{
if (((tmp >> 1) & 1 )!= 0) //找出tmp里为1的位数
{
k = j;//第k位为1
break;
}
}
for (int i = 0; i < 10; i++)
{
if (((arr[i] >> k) & 1) != 0)//第k位为1的异或
{
num1 ^= arr[i];
}
else//第k位为0的异或
{
num2 ^= arr[i];
}
}
printf("%d %d", num1, num2);
return 0;
}