题目内容:
在一个数组中,室友两个数字出现了一次,其他所有数字都出现了两次。找出只出现一次的数字。
如:1,2,3,4,5,1,2,3,4,6 5 和6都只出现了一次,找出5和6打印出来
解题思路:
这里还是要用到异或运算符 ^来解决。不过和单身狗1不一样的是,整个数组异或下来,会出现一个别的值,是由5^6得到的。这里我们找新得到的值的二进制位的1在哪里。
注意,异或运算符是两个数的二进制位对应位相同结果为1,不同为0 ,可以用这点来将两个不同的数字分成两个不同的组,然后在分别异或每个组。
1、找出整体异或的结果
int tmp = 0;
int i = 0;
//将整个数组异或起来,得到两个不同数字的异或结果
for (i = 0; i < n; i++)
{tmp ^= arr1[i];
}
2、找到tmp中,二进制为1 的某一位k
tmp 可能是 0001 0010 0100,所以我们要用到右移运算符 >>
int k = 0;
for (i = 0; i < 32; i++)
{if (((tmp >> i) & 1) != 0){k = i;break;}
}
3、将k位上为1的分为一组遍历异或,最后的值存储到p1或p2中
* p1 = 0;
* p2 = 0;
for (i = 0; i < n; i++)
{if (((arr1[i] >> k) & 1) != 0){*p1 ^= arr1[i];}else{*p2 = arr1[i];}
}
最后来看看完整代码吧
#include <stdio.h>void Fund(int arr1[], int n, int* p1, int* p2)
{int tmp = 0;int i = 0;//将整个数组异或起来,得到两个不同数字的异或结果for (i = 0; i < n; i++){tmp ^= arr1[i];}//2、找到tmp中,二进制为1 的某一位kint k = 0;for (i = 0; i < 32; i++){if (((tmp >> i) & 1) != 0){k = i;break;}}//3、将k位上为1的分为一组遍历异或,最后的值存储到p1或p2中* p1 = 0;* p2 = 0;for (i = 0; i < n; i++){if (((arr1[i] >> k) & 1) != 0){*p1 ^= arr1[i];}else{*p2 = arr1[i];}}
}int main()
{int arr[] = { 1,2,3,4,5,1,2,3,4,6 };int sz = sizeof(arr) / sizeof(arr[0]);int num1 = 0;int num2 = 0;Fund(arr, sz, &num1, &num2);printf("%d %d\n", num1, num2);return 0;
}
结果: