找单身狗1:
一个数组中只有一个数字是出现一次,其他所有数字都出现了两次。
编写一个函数找出这个只出现一次的数字。
例如:
有数组的元素是:1,2,3,4,5,1,2,3,4
只有5出现1次,要找出5
相同的数字异或结果为0,0和任何数异或的结果为该数本身,使用异或可以找出三个数中只出现一次的数字。
同理,在数组中也可以使用异或的方式,将数组所有元素进行异或运算得到的结果.比如一个数组:[1,2,3,4,5,4,3,2,1],则该数组的异或和为:1^2^3^4^5^4^3^2^1.
注意异或运算满足交换律和结合律
int seekSingleDog(int arr[],int sz)
{
int i = 0;
int ret = 0;
for (i = 0; i < sz; i++)
{
ret ^= arr[i];//数组异或和
}
return ret;
}
int main()
{
int arr[] = { 1,2,3,4,5,4,3,2,1 };
int size = sizeof(arr) / sizeof(arr[0]);
int result = seekSingleDog(arr,size);
printf("%d\n", result);
}
找单身狗2:
一个数组中只有两个数字是出现一次,其他所有数字都出现了两次。
编写一个函数找出这两个只出现一次的数字。
例如:
有数组的元素是:1,2,3,4,5,1,2,3,4,6
只有5和6只出现1次,要找出5和6.
第一步:
在数组中寻找两个只出现一次的数字,利用异或的性质,两个相同的数字进行异或就获得到全零,零异或上一个数结果就等于这个数。先把数组元素都进行异或得到的结果等于数组中那两个出现一次的数字异或的值。
第二步:
利用异或的结果对数组进行分组
利用结果中二进制为1的值,可以对数组进行分类,将数组分为两类,并且将只出现一次的数字分别放到两类中。
void seekSingleDog(int arr[], int sz,int *dog1,int* dog2)
{
//1.所有数字异或在一起
int i = 0;
int ret = 0;
for (i = 0; i < sz; i++)
{
ret ^= arr[i];//数组异或和
}
//2.计算ret的结果中第几位是1
int pos;
for (i = 0; i < 32; i++)
{
if (((ret >> i) & 1) == 1)
{
pos = i;再找到有分歧的一位。在这一位上,两个数一定是一个1一个0
break;
}
}
//3.对数组进行分类并且进行异或
for (i = 0; i < sz; i++)
{
if (((arr[i] >> pos)&1) == 1)
{
*dog1 ^= arr[i];
}
else {
*dog2 ^= arr[i];
}
}
}
int main()
{
int arr[] = { 1,2,3,4,5,4,3,2,1,6 };
int size = sizeof(arr) / sizeof(arr[0]);
int dog1 = 0;
int dog2 = 0;
seekSingleDog(arr, size, &dog1, &dog2);
printf("%d %d\n", dog1, dog2);
}
由于,相同的数字异或结果为0,0和任何数异或的结果为该数本身,当我们求出第一个数之后,可以对数组异或的结果和第一个单身狗进行异或,可以求出第二个单身狗。
对第三步代码可以进行改写:
for (i = 0; i < sz; i++)
{
if (((arr[i] >> pos)&1) == 1)
{
*dog1 ^= arr[i];
}
/*else {
*dog2 ^= arr[i];
}*/
}
*dog2 = ret ^ *dog1;