“只出现一次的数字”系列 剑指offer--位运算学习(一)

最近学了下位运算,简单说说收获吧。

首先我们要了解下常见的位运算操作:

  • 与或非操作
    在这里插入图片描述
  • 异或操作
    在这里插入图片描述

进阶规律:与或非 和 异或都是满足结合律的。
在这里插入图片描述
在这里插入图片描述

//重点
a&b&c=ab(b|c)

a^a=0

a^(~a)=1

0^b=b

我们先来看看第一道题:

在这里插入图片描述

做这道题需要一个重要的知识点:

a^b^a=a^a^b=0^b=b

也就是说一堆数一起异或,最后剩下的应该是非偶数重复数的异或和。

上面的问题重复的数都是偶数,就一个不重复的数。我们将它异或,结果就是我们要的数。

代码如下:

class Solution {
    public int singleNumber(int[] nums) {
     int ans =0;
     //求所有数的异或和
    for(int i=0;i<nums.length;i++){
        ans ^=nums[i];
    }
    return ans;
    }
}

第二道题 :数组不重复的数字有两个,我们把它挑出来。

在这里插入图片描述
这道题就比上个题难了一些。
需要用到两个套路。
我们拿 [2,2,3,5]举例子:
我们将数组里的数字异或操作,观察下这个异或值的二进制形式。

0000 0000 0000 0011
0000 0000 0000 0101
-------------------    异或之后
0000 0000 0000 0110

我们发现3 和 4的第二位第三位的值不一样,而且这个位置异或后肯定为1,如果我们以这两位之一为分辨标准,用一个1 进行与操作,就可以将两个数分到不同的组里。再对每组分别求值,就可以得到最终结果。

class Solution {
    public int[] singleNumber(int[] nums) {
    // 第一个不重复的数字
    int a=0;
    //第二个不重复的数字
    int b=0;
    //所有数的异或值
    int xor=0;

    //求出所有数的异或值
    for(int i=0;i<nums.length;i++) xor^=nums[i];

    //定义探针,并且确定两数不同的二进制位
    int div=1;
    while((xor & div)==0) div=div << 1;
    
    //用探针将数分为两组,分别求我们要的两个数 a b
    for(int i=0;i<nums.length;i++){
        if((nums[i] & div)==0) a^=nums[i];
        else b^=nums[i];
    }
    return new int[]{a,b};
     }
}

另外一种解法:

    public static void printOddTimesNums(int[] arr) {
        int eor = 0;

        //让ero = a ^ b

        for(int num : arr){
            eor = eor ^ num;
        }

        //找出从右数第一个为1的位数,也是a和b有差异的位数

        int right = eor & (~eor + 1);

        //将a或者b挑出来

        int eors = 0;
        for (int i = 0; i < arr.length; i++) {
            if ((arr[i] ^ right) != 0) {
                eors = eors ^ arr[i];
            }
        }
        
        //此时 eor = a ^ b eors = a || b 他俩异或求出另外一个 
        
        eor = eors ^ eor;
        // 然后输出eor和eors即可
    }

记住这个:

     //只保留eor从右往左数第一个1的方法

        int right = eor & (~eor + 1);

只出现一次的数字Ⅱ

在这里插入图片描述

class Solution {
    public int singleNumber(int[] nums) {
   int a = 0, b = 0;
    for (int x : nums) {
        b = (b ^ x) & ~a;
        a = (a ^ x) & ~b;
    }
    return b;
    }
}

这题就当记规律了。

        b = (b ^ x) & ~a;
        a = (a ^ x) & ~b;

可以做到三数消除。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值