前言

LeetCode上一道关于位运算的题目数字的补数,原题目如下:

给定一个正整数,输出它的补数。补数是对该数的二进制表示取反。
注意:
  1. 给定的整数保证在32位带符号整数的范围内。
  2. 你可以假定二进制数不包含前导零位。
示例 1:
输入: 5
输出: 2
解释: 5的二进制表示为101(没有前导零位),其补数为010。所以你需要输出2。

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

解题思路

这道题目我解题的思路是先尝试对某个数字取反,然后通过位运算把前导零位取反后的1变回0,以入参为5举例:

  1. 对5(二进制表示为101)取反,获得11111111111111111111111111111010
  2. 要使11111111111111111111111111111010变成101,只需要让

        11111111111111111111111111111010
     &  00000000000000000000000000000111
     ------------------------------------
        00000000000000000000000000000101     

    &为与运算,那么此时的问题就是如何生成前32-3=29(前导零位的位数,注意int应该是31位的,但是这个还把符号位也算上了)个的0和3个1组成的二进制数字了

  3. 00000000000000000000000000000111可以通过以下方式获得~((~0)<<3),简单来说就是

    1. 对0取反获得全为1的二进制制数,即11111111111111111111111111111111
    2. 再左移3位(入参的有效位数),得到11111111111111111111111111111000
    3. 最后取反,得到00000000000000000000000000000111

其实就是使用逆推法来解题。

实现代码

    /**
     * 数字的补数
     * @param num
     * @return
     */
    public int findComplement(int num) {
        //有效位数
        int offset=32-Integer.numberOfLeadingZeros(num);
        return (~num)&(~((~0)<<offset));
    }

Null
137 声望31 粉丝

免费的东西是最贵的,好走的只是下坡路