作业标题
找单身狗2
作业内容
一个数组中只有两个数字是出现一次,其他所有数字都出现了两次。
编写一个函数找出这两个只出现一次的数字。
例如:
有数组的元素是:
1,2,3,4,5,1,2,3,4,6
只有5和6只出现1次,要找出5和6.
2.解题思路
找出一个只出现过一次的数字的问题处理方法就是找一个数字把里面所有的数字都异或一遍,利用异或两次等于没异或的特点来处理。那么如果有两个数字都只出现了一次,那么如此得到的应该是两个数异或的结果。(异或:相同为0,不同为1)
首先这个结果肯定不是0
(要不然就全都配对了),所以里面一定至少一位是一。找出值为1
的一位,以这一位的值将结果分为两组。例如1 2 3 4 1 2
,异或完的结果应该是3^4
得到的111
,那么随便找一位就行了。例如找最低位,那么这一位是1
的有1 3 1
,是0
的有2 4 2
,由于是利用异或结果为1
的某一位分的组,所以两个待查询数字一定分别在两组中。所以再找两个变量,分别异或两组数,即可找到这两个数。
void findTwoNum(int arr[], int n, int* pnum1, int* pnum2)
{
int i;// 循环变量
int sum = 0;// 用于存储所有数异或的结果
for (i = 0; i < 9; i++)// 第一个for循环:计算数组中所有数的异或结果
{
sum ^= arr[i];
}
int pos;// 用于存储第一个为1的位的位置
for (i = 0; i < 32; i++)// 第二个for循环:找到异或结果中第一个为1的位
{
if (sum & 1 << i) // 检查sum的第i位是否为1
{
pos = i;// 找到第一个为1的位
break;// 跳出循环
}
}
*pnum1 = *pnum2 = 0;// 初始化两个数为0
for (i = 0; i < 10; i++)// 第三个for循环:根据第一个为1的位,将数组中的数分配到两个不同的数中
{
if (arr[i] & 1 << pos)// 检查arr[i]的第pos位是否为1
{
*pnum1 ^= arr[i]; //这一位是1的,放在数1里
}
else
{
*pnum2 ^= arr[i]; //这一位是0的,放在数2里
}
}
printf("%d %d\n", *pnum1, *pnum2);
}
int main() {
int arr[] = { 1,2,3,4,2,1 };
int n = sizeof(arr) / sizeof(arr[0]);
int num1, num2;
findTwoNum(arr, n, &num1, &num2);
return 0;
}
打印:
3 4