【算法-位运算】求数字的补数

1. 题目

476. 数字的补数

对整数的二进制表示取反(0 变 1 ,1 变 0)后,再转换为十进制表示,可以得到这个整数的补数。

  • 例如,整数 5 的二进制表示是 “101” ,取反后得到 “010” ,再转回十进制表示得到补数 2 。

给你一个整数 num ,输出它的补数。

示例 1:

输入: num = 5
输出: 2
解释: 5 的二进制表示为 101(没有前导零位),其补数为 010。所以你需要输出 2 。

示例 2:

输入: num = 1
输出: 0
解释: 1 的二进制表示为 1(没有前导零位),其补数为 0。所以你需要输出 0 。

提示:

  • 1 <= num < 2^31

2. 思路

这道题的逻辑是数字取反,而不是求补码,那么来看下图图解。
在这里插入图片描述
这里的取反是需要找到最高位的 1 然后取反,所以核心逻辑就是如何找到最高位1,如果要找到最高位 1,有两种方法。

第一种方法就是遍历这个 num 的所有位,找到第一个不为空的位,然后直接 break

int index = -1;
for(int i = 31; i >= 0; i--){
    if(((num >> i) & 1) != 0){
        index = i;
        break;
    }
}

找到这个 index 之后,我们就可以继续遍历从 0 到 index,将这部分数据取反即可。

int res = 0;
for(int i = 0; i <= index; i++){
    if(((num >> i) & 1) == 0){
        res |= (1 << i);
    }
}
return res;

上面这种方法需要遍历所有位,那么有没有更方便的方法呢? 还是看下下面图解。
在这里插入图片描述
上面我们以 57 为例子,最终 x = 32,这个 32 就是我们要找的最高位。我们找到这个最高位 32 后,再将 32 - 1,因为最高位取反后肯定为 0,所以换句话说就是要求出剩下的位里面有哪些位是 1,32 - 1 就是将剩下这些位全部变成 1。
在这里插入图片描述
然后将这个数和 ~num 相与,这样求出来结果了。
在这里插入图片描述


3. 代码

首先是第一种方法,第一种方法就比较简单了,直接遍历即可。

public int findComplement(int num) {
    //1.找到最高位的1,然后从小到大逐位取反
    int index = -1;
    for(int i = 31; i >= 0; i--){
        if(((num >> i) & 1) != 0){
            index = i;
            break;
        }
    }
    int res = 0;
    for(int i = 0; i <= index; i++){
        if(((num >> i) & 1) == 0){
            res |= (1 << i);
        }
    }
    return res;
}

第二种方法,从上面的图解中可以看到核心逻辑就是找到最低位的 1,每一次都相减,那么如何找到最低位 1 呢?这就涉及到位运算公式:x & -x 了。
在这里插入图片描述
上面求出了 -num 的值,那么最后再将 num 和 -num 相与,就能求出最低位了。
在这里插入图片描述
好了,上面求出最低位了,最后直接用 -num & (x - 1)直接相与就能求出取反的结果了,下面给出第二种方法的代码:

public int findComplement(int num) {
    int x = 0;
    for(int i = num; i != 0; i -= lowbit(i)){
        x = i;
    }
    //将num的前x-1位取反,因为前面32-x位都是0,所以不用管
    return ~num & (x - 1);
}

//获取当前字符最低位的1
public int lowbit(int x){
    return x & -x;
}

这种方法的计算次数比第一种方法少了几种计算次数,效率更高。


4. 小结

这是灵神题单位运算的一条,这里就记录下思路和所用到的位运算公式:

  • 求最低位 1:x & -x




如有错误,欢迎指出!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值