Given a positive integer, output its complement number. The complement strategy is to flip the bits of its binary representation.
Note:
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.
给定一个正整数,输出它的补数。补数是对该数的二进制表示取反。
注意:
示例 1:
输入: 5
输出: 2
解释: 5的二进制表示为101(没有前导零位),其补数为010。所以你需要输出2。
示例 2:
输入: 1
输出: 0
解释: 1的二进制表示为1(没有前导零位),其补数为0。所以你需要输出0。
思路一:计算出num的原码,再取反求补数。
C++实现:
class Solution {
public:
int findComplement(int num) {
vector temp;
while(num)
{
temp.push_back(num%2);
num /= 2;
}
int sum = 0 , j = 0;
for(int i = 0; i < temp.size(); i++)
{
temp[i] = temp[i] > 0? 0 : 1;
sum += temp[i]*pow(2,j);
j++;
}
return sum;
}
};
C++代码实现二:
class Solution {
public:
int findComplement(int num)
{
int tmp = num, count = 0;
if(num == 0)
return 1;
while(tmp)
{
tmp = tmp &(tmp -1);
count++;
}
for(int i = 0; i < 32 && count; i++)
{
if(num & (1 << i))
{
count--;
}
else
{
tmp |= (1 << i);
}
}
return tmp;
}
};
思路二:
如果我们能知道该数最高位的1所在的位置,就可以构造一个长度和该数据所占位置一样长的一个掩码mask,然后概述和mask进行异或即可。
例如:5的二进制是101,我们的构造的掩码为mask=111,两者异或则为010,即是所要的结果。这里和计算机网络中IP地址的子网掩码比较相似,如10的二进制为0000 1010,其掩码为0000 1111,1表示二进制的有效位,两者进行异或时恰好等同于对原码取反(因为掩码有效位始终为1,则当原码中为1时 异或为0 ,原码中为0时 异或为1)。那么如何求得该数的掩码呢,由0001 0000 - 0000 0001 = 0000 1111可看出,只要求得num二进制的最高位,将该位再左移一位,减1即可得到该数的掩码。
java代码实现一:
public class Solution {
public int findComplement(int num) {
int mask = 1, temp = num;
while(temp > 0) {
mask = mask << 1;
temp = temp >> 1;
}
return num^(mask-1);
}
}
java代码实现二:
public class Solution {
public int findComplement(int num) {
int mask = (Integer.highestOneBit(num) << 1) - 1;
return num^mask;
}
}
Integer.highestOneBit(i)是一个什么样的函数呢?通过查看文档得知,这个函数的作用是取 i 这个数的二进制形式最左边的最高一位且高位后面全部补零,最后返回int型的结果。
来看下 Integer.highestOneBit (i) 这个函数的实现代码:
publicstaticinthighestOneBit(int i) {
// HD, Figure 3-1
i |= (i >> 1);
i |= (i >> 2);
i |= (i >> 4);
i |= (i >> 8);
i |= (i >> 16);
return i - (i >>> 1);
}1、第一步的作用是把最高位1右移移位,并与原数据按位取或。那么这就使得最高位和它的下一位是连续两个1。
2、第二步的作用是把刚刚移位得到连续两个1继续右移两位并与原数据按位取或。那么这就使得最高两位和它的下两个连续位组成四个连续的1。
3、 以此类推,最终得到的i是从开始的最高位到结束全是1。并减去i不带符号的右移一位,即可得到一个int数据的最高位的值。
4、上述情况是针对于i不为零和负数的情况,如果i为零,那么得到的结果始终为零。如果i位负数,那么得到的结果始终是-2147483648。即等于Integer.MIN_VALUE。(原因在于负数的最高位始终为1,即是负数的符号位)
此函数的最重要理解点在与要始终把握二进制的最高位进行运算处理,那么对于函数中的右移一位、两位、四位、八和十六位就好理解了。同理,对于long类型的取最高位运算应该需要加一条语句 i|=(i>>32); 原因在于long类型在Java中是64位的。
Long类型的hightestOneBit(i)代码如下:public static long highestOneBit(long i) {
// HD, Figure 3-1
i |= (i >> 1);
i |= (i >> 2);
i |= (i >> 4);
i |= (i >> 8);
i |= (i >> 16);
i |= (i >> 32);
return i - (i >>> 1);
}
java代码实现三:
public class Solution {
public int findComplement(int num) {
return ~num & (Integer.highestOneBit(num) - 1);
}
}
java代码实现四:
public class Solution {
public int findComplement(int num) {
char[] ch = Integer.toBinaryString(num).toCharArray();
int ret = 0;
for(int i = 0; i < ch.length; i++) {
if(ch[i] == '0') {
ret += Math.pow(2, ch.length - i - 1);
}
}
return ret;
}
}
java代码实现五:
class Solution {
public int findComplement(int num) {
String str=Integer.toBinaryString(num);
char[] a=str.toCharArray();
char[] b=new char[a.length];
for(int i=0;i