前言
LeetCode上一道关于位运算的题目数字的补数,原题目如下:
给定一个正整数,输出它的补数。补数是对该数的二进制表示取反。
注意:
- 给定的整数保证在32位带符号整数的范围内。
- 你可以假定二进制数不包含前导零位。
示例 1:
输入: 5
输出: 2
解释: 5的二进制表示为101(没有前导零位),其补数为010。所以你需要输出2。示例 2:
输入: 1
输出: 0
解释: 1的二进制表示为1(没有前导零位),其补数为0。所以你需要输出0。
解题思路
这道题目我解题的思路是先尝试对某个数字取反,然后通过位运算把前导零位取反后的1变回0,以入参为5举例:
- 对5(二进制表示为101)取反,获得11111111111111111111111111111010
-
要使11111111111111111111111111111010变成101,只需要让
11111111111111111111111111111010 & 00000000000000000000000000000111 ------------------------------------ 00000000000000000000000000000101
&为与运算,那么此时的问题就是如何生成前32-3=29(前导零位的位数,注意int应该是31位的,但是这个还把符号位也算上了)个的0和3个1组成的二进制数字了
-
00000000000000000000000000000111可以通过以下方式获得
~((~0)<<3)
,简单来说就是- 对0取反获得全为1的二进制制数,即
11111111111111111111111111111111
- 再左移3位(入参的有效位数),得到
11111111111111111111111111111000
- 最后取反,得到
00000000000000000000000000000111
- 对0取反获得全为1的二进制制数,即
其实就是使用逆推法来解题。
实现代码
/**
* 数字的补数
* @param num
* @return
*/
public int findComplement(int num) {
//有效位数
int offset=32-Integer.numberOfLeadingZeros(num);
return (~num)&(~((~0)<<offset));
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。