单身狗(异或运算)
Posted 再吃一个橘子
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了单身狗(异或运算)相关的知识,希望对你有一定的参考价值。
问题描述:
一个数组中只有两个数字是出现一次, 其他所有数字都出现了两次。 找出这两个只出现一次的数字,编程实现。
问题分析:
1.先从数组遍历异或的结果开始
(1)两个相同的数异或的结果是0;
(2)所有不为0的数和0异或的结果是本身。
综上两点,一个整型数组中,若只有两个数字只出现一次,其他数字都出现了两次,那么把数组中的所有遍历异或一遍的结果就是只出现一次的两个数字相异或的结果。
先定义一个上述的数组。
int arr[] = { 1, 2, 3, 3, 2, 1, 4, 5 };
可以看到,只有4、5两个数只出现了一次,其他数都出现了两次,那么根据上述分析,把该数组中所有的元素都遍历异或一遍所得的结果就是4和5相异或的结果。
2.把数组中所有的元素分组
为了方便分析,先把数组中所有元素的二进制表示写出来:
1:> 0001
2:> 0010
3:> 0011
4:> 0100
5:> 0101
4和5相异或的结果: 0001
可以看到4和5相异或的结果为0001。我们都知道,两个数相异或的结果中的“1”表示这两个数在该位上不同,就像4(0100)和5(0101)的第一个二进制位不同。
接下来,我们就每个数的第一个二进制位进行分类,这样分类的好处是可以天然把该数组中两个只出现一次的数分开,可以分成两种情况:
1.第一个二进制位为0
2(0010)、2(0010)、4(0100)
2.第一个二进制位为1
1(0001)、 1(0001)、3(0011)、3(0011)、5(0101)
3.接下来,我们再使用《当一个整型数组中只有1个数字出现一次,其他数字出现两次,找出这个数字》的思想就上述分类分别求解即可得到两个只出现一次的数字。
源代码:
#include<stdio.h>
#include<windows.h>
void Find(int arr[], int len)
{
int num1 = 0;
int num2 = 0;
int ret = 0;
int n = 0;
int i = 0;
int bit = 0;
for (i = 0; i < len; i++)
{
ret = ret ^ arr[i];
}
for (n = 0; n < 32; n++)
{
if ((ret >> n) & 1 == 1)
break;
}
for (i = 0; i < len; i++)
{
if ((arr[i] >> n) & 1 == 1)
num1 = num1 ^ arr[i];
else
num2 = num2 ^ arr[i];
}
printf(" num1=%d\\n num2=%d\\n", num1, num2);
}
void main()
{
int a[] = { 1, 2, 3, 3, 2, 1, 4, 5 };
int len = sizeof(a) / sizeof(a[0]);
Find(a, len);
system("pause");
return 0;
}
代码优化:指针
#include<stdio.h>
#include<windows.h>
void Func(int *arr, int len, int *px, int* py)
{
int i = 0;
int num = 0;
int pos = 0;
for (i = 0; i < len; i++)
{
num ^= arr[i];
}
//整体异或的结果,存放到了num
for (i = 0; i < 32; i++)
{
if (1 == ((num >> i) & 1))
{
pos = i;
break;
}
}
//分组异或
for (i = 0; i < len; i++)
{
if (((arr[i] >> pos) & 1) == 1)
{
*px = *px^arr[i];
}
else{
*py = *py^arr[i];
}
}
}
int main()
{
int arr[] = { 1, 3, 2, 4, 1, 5, 3, 4 };
int len = sizeof(arr) / sizeof(arr[0]);
int x = 0;
int y = 0;
Func(arr, len, &x, &y);
printf("%d,%d\\n", x, y);
system("pause");
return 0;
}
转载博主:Angus_lxy
以上是关于单身狗(异或运算)的主要内容,如果未能解决你的问题,请参考以下文章