-
这里我们首先了解二进制数位异或的一些性质
-
1.相同数字异或为0.(0 ^ 0 = 0, 1 ^ 1 = 0)
-
2.相反数字异或为1.(1 ^ 0 = 1)
-
3.和 0 异或结果不变( 1 ^ 0 = 1 , 0 ^ 0 = 0)
-
4.和 1 异或结果相反( 1 ^ 1 = 0, 0 ^ 1 = 1)
不妨将其推广到十进制数当中: -
1.相同的十进制数异或结果为 0
-
例如:5 ^ 5 = 0
- 2.两个大小不同的数字异或之后结果一定不是0
- 例如: 3 ^ 5 = 6
- 3.和 0 异或结果不变
对于这个问题,假设给定的数组是 [ 1,3,3,4,4,6]
大体的思路就是将数组根据1和6的某一位比特位不同分成两组。得到这样的两组数:
第一组: 1,3,3
第二组: 6,4,4
代码如下:
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
int* singleNumbers(int* nums, int numsSize, int* returnSize){
//通过异或数组当中的每个元素求出那两个数字异或的结果ret ,ret != 0
//那么ret的二进制序列中一定有一位是 1(即:这两个数字的二进制序列在该比特位上一个是1 另一个是0)
//将该位是1的分为一组,是0的分为一组,再将这两组数分别异或即可的到最终结果。
int ret = 0;
for (int i = 0; i < numsSize; i++)
{
ret ^= nums[i];//ret是两个只出现一次的数异或的结果
}
int pos = 0;
while (pos < 31)
{
if (ret & (1 << pos)) // ret按位与 1 << pos 位来判断哪一比特位是1。
{
break;
}
pos++;
}//最终得到的pos就是那两个只出现一次的数比特位不同的那一位
int *returnNums = (int *)malloc(sizeof(int)* 2);//存放只出现一次的那两个数
returnNums[0] = 0;
returnNums[1] = 0;// 初始化为0 .因为任何书异或0都是它本身
for (int i = 0; i < numsSize; i++)
{
if (nums[i] & (1 << pos))
{
returnNums[0] ^= nums[i];//数组当中第pos位不是0的数异或得到结果
}
else
{
returnNums[1] ^= nums[i];//数组当中第pos位是0的数异或得到结果
}
}
*returnSize = 2;
return returnNums;
}