476. Number Complement
Given a positive integer, output its complement number. The complement strategy is to flip the bits of its binary representation.
Note:
The given integer is guaranteed to fit within the range of a 32-bit signed integer.
You could assume no leading zero bit in the integer’s binary representation.
Example 1:
Input: 5
Output: 2
Explanation: The binary representation of 5 is 101 (no leading zero bits), *and its complement is 010. So you need to output 2.
Example 2:
Input: 1
Output: 0
Explanation: The binary representation of 1 is 1 (no leading zero bits), and its complement is 0. So you need to output 0.
看到complement第一反应是求数的补码(2’complement),即为二进制按位取反之后加1,然而看例子和具体描述,这道题应该求的是反码(1’complement),即仅二进制按位取反即可,不要弄错概念。
这道题的内容十分简单,就是已知一个十进制数,求出它的反码(十进制表示)。最简单的方法就是先将这个十进制数分解成二进制数,之后按位取反再乘以2的对应次方再相加,直接求出它的反码。使用数组或者是栈储存二进制数的每一位都可以。
参考代码如下:
class Solution {
public:
int findComplement(int num) {
stack<int> s;
int complement = 0;
while(num != 0) {
s.push(num % 2);
num /= 2;
}
int count = s.size();
for(int i = count - 1; !s.empty(); i--) {
complement += (1 - s.top()) * pow(2, i);
s.pop();
}
return complement;
}
};
当然,我们还有更巧妙的方法。在计算机当中,任何十进制数其实都是按二进制来存放的,我们完全可以想到“~”运算符——按位取反。但同时我们会遇到一个问题,~运算符是对每一位都按位取反。假设我们输入的是5,它的二进制数是101,在计算机中的表示是000…101,101的前面一共有29个0。也就是说,当我们使用~运算符进行按位取反操作,前面的29个0也会被取反变成了1,~5 = (111…010)2,这就变成不是我们所想要的结果,我们需要提取出我们需要的后3位,让前面置零。
我选择的方法是使用移位,在一开始记录下我们需要的位数,记为有效位数(count),然后通过先左移(32-有效位数)位,再右移相同位数,自动系统补零从而得到我们想要的结果。
参考代码如下:
class Solution {
public:
int findComplement(int num) {
int length = 0;
int temp = num;
while(temp != 0) {
length++;
temp >>= 1;
}
num = ~num;
num <<= (32 - length);
num >>= (32 - length);
return num;
}
};
另外膜拜一下discuss里面巨佬的思路,十分巧妙的使用了取反、按位与操作仅用3行边完成了这道题。首先通过mask=~0使mask全为1,之后利用while(mask&num) mask <<=1 使得mask变成111…100…000的形式,其中0的位数与num的二进制位数相同,也就是提取出了有效位数,之后利用~mask & ~num将~num中我们需要的位数提取出来,从而获得答案。真的是一个很巧妙的方法。