给定一个整数数组nums,其中恰好有两个元素只出现一次,其余所有元素均出现两次,请找出只出现一次的那两个元素。你能否仅使用常数空间复杂度来实现?
示例 : 输入:num=【1,2,2,3,3,4】 输出:1,4
题目给定初始程序为
intsingleNumber( int nums, int numsSize, int*returnSize )
{
}
思路一:要想从数组中得到那两个数,我们可以将数组中所有元素***异或***,这样想的的两个数都异或为0了,只留下只出现一次的那两个元素。
## 实现
int*singleNumber( int* nums, int numsSize, int*returnSize )
{
int ret=0;//0和如何元素异或都不会改变其结果,我们用0去异或
for(int i=0;i<numsSize;i++)
{
ret^=nums[i];
}
}
通过以上步骤,此时我们得到的ret是那两个元素的异或,并不是独立的两个元素,现在我们应该思考如何把那两个元素拆出来呢?
显然,要想从ret中拆出独立的两个元素非常困难,我们可以换个思路,既然ret是那两个元素的异或,那么在ret的二进制一个位置上(如M位)为1,必然两个元素(假设为x1,x2)其中一个的M位为1,另一个为0(异或时,相同为0,相异为一,二进制仅有0和1两种表示方法)。想到这里,那我们可以将原先数组中M为1的分成一组,M位为0的分成一组,相同的元素,必然会分到同一组,再让为1的一组全部异或得到其中一个独立元素,M为0的一组全部异或,得到另一个独立元素。
实现:
int*singleNumber( int* nums, int numsSize, int*returnSize )
{
int ret=0;//0和如何元素异或都不会改变其结果,我们用0去异或
for(int i=0;i<numsSize;i++)
{
ret^=nums[i];
}
int m=0;//找出ret第m位为1
while(m<32)
{
if(ret&(1<<m))//与上1左移m位,ret中一定有一位是1,只需要不断地将m左移一位,当第ret的第m位为1时,if语句里不为0,进入if,break跳出去,得到m的值
break;
else
++m;
}
//做完以上步骤,我们接下来分离ret中所有m位为1和m位为0的元素,其中一组为x1,另一组为x2
int x1=0,x2=0;
for(int j=0;j<numsSize;j++)
{
if(nums[j]&(1<<m))
{
x1^=nums[j];//m为1进入if,到x1相互异或,最后相同的消失,只剩一个m位为1的独立元素
}
else
{
x2^=nums[j];//m为0不会进入if,到x2相互异或,最后相同的消失,只剩一个m位为0的独立元素
}
}
int*retArr=(int*)malloc(sizeof(int)*2);
retArr[0]=x1;
retArr[1]=x2;
*returnSize=2;
return retArr;
}
创作不易,点个赞支持一下吧!不定期发表自我感悟以及面试真题,感兴趣的兄弟们点波关注哦!感谢大家观看,谢谢,谢谢,谢谢!