关于位运算的相关算法

前言:

在计算机中,很多时候,位运算的效率要比普通的数学运算的效率高很多,因为计算机的本质就是二进制的。

今天我们来分享下,在面试中,出现的高频的位运算算法题。

题目一

题意: 给定一个数组,里面只有一个数字出现了一次,其他数字都出现了两次,找到这个出现一次的数字。

思路: 没有接触过位运算的面试者,很有可能就想到了哈希表来实现,记录每种数字出现的次数,最后找到出现一次的即可。但是这种做法不但时间复杂度很高,还利用了额外的空间,那有没有更好的办法呢?答案就是异或运算

异或运算的规则:

两个数字进行异或运算,如果不一样,就返回1, 如果一样,返回0。

举例子: 1 ^ 0 = 1 0 ^ 1 = 1 1 ^ 1 = 0 0 ^ 0 = 0

可以看出来,还是很简单的,这里,左神算法里面提到了一个更好的想法,他认为异或运算就是不进位的相加,大家可以品一品。

所以这道题目我们就可以对整个数组遍历,做异或运算,最后偶数个数的数字都会消掉变成0。最后就剩下哪个只出现1 次的数字了。代码如下

 public int findOdd(int [] nums) {
        int ans = 0;
        for (int num : nums) {
            ans ^= num;
        }
        
        return ans;
    }

题目二

题意: 给定一个数组,有两个数出现了奇数次,其他的数字都是出现了偶数次,找到这两个数分别是什么

前置知识:解决这道题目我们需要知道一个小知识点。

给定一个二进制数,你怎么能拿到它最右边的1.

举例: 0010 1100 -> 0000 0100

这个如何去实现呢? 其实我们可以通过对这个数取反后再 + 1 就可以得到了。

思路: 我们可以对这个数组遍历并异或一边,根据前面的知识,最后我们获得的数组num = a ^ b,因为其他偶数个的数字都消除掉了。

接着,我们拿到这个num 数字最右边的1, 假定这个数字是k, 那么这个K可以把整个数组分为两类,通过与运算取实现即可。然后我们用其中一类去异或运算num就可以得到其中一个数a,那么B也就出来了,看下代码。

public void findOdd(int [] nums) {
        int eor = 0;
        for (int num : nums) {
            eor ^= num;
        }

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

        int a = 0;
        for (int j : nums) {
            if ((rightOne & j) == 0) {
                a ^= j;
            }
        }
        
        int b = eor ^ a;
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值