【面试题】【剑指offer】给定一个整数数组nums,其中恰好有两个元素只出现一次,其余所有元素均出现两次,请找出只出现一次的那两个元素。

给定一个整数数组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去异或
       forint 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;
}

创作不易,点个赞支持一下吧!不定期发表自我感悟以及面试真题,感兴趣的兄弟们点波关注哦!感谢大家观看,谢谢,谢谢,谢谢!

猜你喜欢

转载自blog.csdn.net/weixin_54748281/article/details/115315831