剑指offer--查询只出现一次的数字

题目:一个整形数组里面,只有两个数字出现了一次,其他的数字都出现了两次,求只出现一次的数。

分析:首先考虑这个问题的一个简单版本,一个数组里除了一个数字外,其他的数字都出现了两次。请写程序找出只出现一次的数字?

        这个问题的突破口在哪里?为什么别的数字都是出现了两次?这里就是为了让我们想到异或运算的性质:任何一个数字异或它自己都等于0,若没有这个特性,我们可以循环遍历数组,给每个出现的数记一次数,可以用hashmap的key,value实现。但是有了这个特性我们就要想到更高效的算法。即从头到为依次异或数组中的每一个数字,那么最终的结果刚好是那个只出现一次的数字,出现两次的数字全部在异或中抵消掉了。

        有了上面这个简单的解决方案之后,回到原始问题。我们能不能把原数组分为两个子数组。每个子数组中,包含一个只出现一次的数字,而其他数字都出现了两次,如果能这样拆分原数组,按前面的办法就可以分别求出这两个只出现一次的数字。

        所以,第一步还是从头到尾依次异或数组中的每一个数字,那么最终得到的结果就是两个只出现一次的数字的异或结果。因为其他数字都出现了两次,在异或中全部抵消掉了。第二步,由于这两个数字肯定不一样,那么异或结果肯定不为0,也就是说这个结果数字的二进制表示中至少有一位是1.,所以我们在异或结果数字中找到第一个1的位置,记为第N位。第三步,以这第N位为标准将数组分为两个部分。在二进制第N位为1的都放在一个数组,为0的放到另一个数组,这样两个子数组中就各包含一个只出现一次的数字,这边大家要想一下,因为是进行异或操作,所以在第N位,两个只出现一次的数字肯定不一样,有了这个异或的性质才能这样分组。

//num1,num2分别为长度为1的数组。传出参数
//将num1[0],num2[0]设置为返回结果
public class Solution {
     public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) {
       if(array==null ||array.length<2)
           return ;
       int temp = 0;
//依次异或数组中的数,得到结果为两个只出现一次的数字的异或结果
       for(int i=0;i<array.length;i++)
           temp ^= array[i];
        //获取第一个1在异或结果中出现的位置
       int indexOf1 = findFirstBitIs(temp);
       for(int i=0;i<array.length;i++){
            //异或第一个数组得到第一个出现一次的值
           if(isBit(array[i], indexOf1))
               num1[0]^=array[i];
           else
               num2[0]^=array[i];
       }
   }
    
//获取第一个1在异或结果中出现的结果
public int findFirstBitIs(int num){ int indexBit = 0;
        //num只要还不为0,就右移1为,计数Index+1,这样就可以得到第一个1出现的位置
       while(((num & 1)==0) && (indexBit)<8*4){
           num = num >> 1;
           ++indexBit;
       }
       return indexBit;
   }
//判断第N为是否为1,作为分类标准
   public boolean isBit(int num,int indexBit){
       num = num >> indexBit;
       return (num & 1) == 1;
   }

}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值