一个整型数组 nums 里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。
方法:位运算(异或和按位与)
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
int* singleNumbers(int* nums, int numsSize, int* returnSize){
int ret = 0;
for(int i = 0;i<numsSize;i++)
{
ret^=nums[i];
}
int k = 0;
while(((ret>>k)&1)!=1)
{
k++;
}
int ret1 = 0,ret2 = 0;
for(int i = 0;i<numsSize;i++)
{
if(((nums[i]>>k)&1)==1)
{
ret1^=nums[i];
}
else
{
ret2^=nums[i];
}
}
int* retArr = (int*)malloc(sizeof(int)*2);
retArr[0] = ret1;
retArr[1] = ret2;
*returnSize = 2;
return retArr;
}
思路:
-
首先将数组里的所有数都按位异或,由于有两个数不同。因此结果会是这两个不同的数的异或。
-
下一步我们就要将这两个数字分开,怎么分开呢?
我们看异或后得到的数字,看它第几位是1.(因为异或后得到1可以推出两个不同的数的这一位二进制不同)。 -
然后我们遍历数组,把这一位是1的放在一边,这一位是0的放在另一边。并将两边分别异或。由于这两个不同的数这两位二进制位不同,因此它们肯定在不同的两边,这样就分开了。
-
对两边的数分别进行异或。剩下的数肯定都是成双成对出现了,异或就能消掉。
-
然后再把这两个数放进retArr里
注:由于位运算符的优先级很低很低,比赋值运算符还低。因此在移位的时候要用括号括起来。这里是大坑,博主踩过很多次了!!!