剑指 Offer 56 - I. 数组中数字出现的次数-分组异或

1.题目

2.思路

首先看数据大小10的5次方,题目要求时间复杂度O(n),空间复杂度O(1)。如果是哈希表,显然不符合空间复杂度,所以就向位运算方面思考。

假如题目中只有一个数出现了1次,其余都出现了2次,是不是直接就可以遍历所有的数,用一次异或,就可以得到这个数字了。(或者借用剑指 Offer 56 - II. 数组中数字出现的次数 II的思路,用与操作,求和然后%2是否等于0.)

异或:2 ^ 2 ^ 3 = 3。这是前提。

第一步还是得计算所有的数字的异或结果得到a ^ b.

第二步是想办法把a 和 b , 分成两组,分别进行异或就可以得到a 和 b。

那么问题来了,如何分组?假如数字是[4,1,4,6]

第一次异或得到1 异或 6 = 7 (111)

然后获取最低位的1是 第1位,那么根据这个第1位是否为1,来划分成两个组,一个组里肯定有1.一个组里肯定有6。然后每个组里的数字分别进行异或就可以得到1 和 6.

class Solution {
    public int[] singleNumbers(int[] nums) {
        int n = nums.length;
        int temp = 0; //记录a 异或 b 的结果。
        for(int i = 0 ; i < n ; i++)
            temp ^= nums[i];
        // 分组两组异或,每一组可以得到一个数
        int g1 = 0, g2 = 0;
        int cnt = 0; // 根据第i位低位不为0的位置分割成两组数字。
        for(int i = 0; i < 32 ; i++){
            int t = (temp >> i & 1);
            if(t == 1){
                cnt = i ;
                break;
            } 
        }
        for(int i = 0; i < n; i++){
            if((nums[i] >> cnt & 1) == 1)
                g1 ^= nums[i];
            else
                g2 ^= nums[i];
        }
        return new int[]{g1, g2};
    }   
}

3.结果

4.总结 

问题由浅入深,循序渐进。

先思考只有一个数出现次数为1,其余都出现两次的情况。

紧接着问题关键是要分成两组,分别进行异或操作才可以。

分组的关键在于如何把这两个不同的数分开,想一想这两个数的不同点是啥。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值