剑指Offer之数组中数字出现的次数

题目描述:

一个整型数组 nums 里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。
示例 1:
输入:nums = [4,1,4,6]
输出:[1,6] 或 [6,1]

题目分析:

我们可以将所有的元素进行 ^ 操作,结果为出现了1次的2个元素相 ^ 的结果res,那么怎么分别得到这2个数字呢?

我们可以设置临时变量t = 1;让 t 和 res进行 & ,如果t & res == 0,t<<1;否则直到t & res == 1,即找到了res中由低位到高位第1个1时停止。

因为所有的元素中只有2个元素不同,那么异或后的res肯定不为0,那么说明res中至少有1位为1,这说明2个只出现1次的元素的某一对应位置的元素一个数字0,一个为1,所以,我们可以将为0的分为一组进行,为1的分为一组进行异或,其他元素都出现2次,所以被分到同一个组,^的结果为0,所以每组最后的结果都是出现1次的那个数。

简要概括:

3步走策略:
(1)将所有的数字进行异或,结果为res;
(2)根据res寻找不同的两个数中哪一位为1。 将t(初始值为1)&res,若等于0,t<<1,重复上述工作;否则停止;
(3)根据(2)中为1的那一位进行分组,这样不同的2个数就被分在不同的组,分组中的元素进行^操作,结果就是所求元素。

参考代码:

 public int[] singleNumbers(int[] nums) {
    if(nums == null || nums.length == 0)return new int[]{};
    int res = 0;
    for(Integer num : nums){
       res ^= num;
    }
    int t = 1;
    while((res & t) == 0){
      t <<= 1;
    }
    int ans1 = 0;
    int ans2 = 0;
    for(int i = 0; i < nums.length; i++){
       if((nums[i] & t) == 0)ans1 ^= nums[i];
       else ans2 ^= nums[i];
    }
    return new int[]{ans1, ans2};
 }

注意:

int res = 0;//这里必须注意
    for(Integer num : nums){
       res ^= num;
    }

res初始值为0,因为0异或任何数都等于原数


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值