剑指Offer56-1|数组中数字出现的次数

题目:一个整型数组 nums 里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。

 思路:要求时间复杂度O(n),不能用for循环嵌套遍历;空间复杂度O(1),不能使用Hashset。

此处使用位运算。

eg:若题目改为,数组中只有一个数字出现了一次,其他出现了多次,输出那个只出现了一次的数字。则考虑到两个相同的数字异或为0,而0与任何数字a异或:a^0 =a,则将所有数字全部异或,得到a。

假设数组中x,y只出现了一次,因为x,y不同,此处将所有数字异或起来,得到结果n = x^y;

则x,y中必然有一位是相异的(一个是1,一个是0)。现在我们找到最低相异的那一位:

int m = 1;        
while((n & m) == 0){//说明最后一位是0,不然说明最后一位是1
            m = m<<1;
        }

若n & m == 1,说明最后一位为1,若n & m == 0,说明最后一位为0;将m左移,n与10(二进制)进行与预算,判断倒数第二位是否为1,若是则得到10(二进制),不是则得到0,将m左移。

此时依据num & m的结果是0还是000100...(这种非零结果)(即找到的x与y相异的那一位),可以将数组划分为两组(看那一位是1还是0),其中相同的数字必然分在同一组,x,y分在不同组(那一位相异)。

再将这两组数分别异或,即可以得到x,y!

class Solution {
    public int[] singleNumbers(int[] nums) {
        int x = 0,y = 0,n = 0,m = 1;
        for(int num : nums){
            n = n^num;
        }//全部异或一遍,得到x^y;

        //找到x^y最低不同的那一位!,即x^y最低为1的那一位,右半部分赋值给m(即找到那一位)
        while((n & m) == 0){//说明最后一位是0,不然说明最后一位是1
            m = m<<1;
        }
        for(int num : nums){
            if((num & m) != 0) x = x^num;//相同的数必然能分到同一组,x,y必然能分到两个组,因为那一位不同
            else y = y^num;
        }
        return new int[] {x,y};
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值