版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u012668018/article/details/60760284
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.
题设的要求就是把一个正数的各个二进制位取反,取反的意思就是0变1,1变0,比如101变成010,可以看出,取反之后与原数相加就是111。
所以解题思路也很简单,就是找出这个和,减去原数就行了。问题在于如何找到这个和?因为不同的输入,对应的和的二进制中1的个数是不同的。然而可以确定的是,这个和的二进制位数和原数是一致的。所以只要求得原数的位数,就可以算出这个和。我的思路如下:
public int findComplement(int num) {
int tmp = num, bits = 0;
while(tmp > 0) {
bits++;
tmp = tmp >> 1;
}
int sum = 1 << bits - 1;
return sum - num;
}
while循环中通过右移运算求出原数的位数;然后通过1左移bits个位,得到对应和加1那个值,所以要减去1才是对应的和,然后返回和减去原数。
这种思路是比较原始和直观的,接着做一点优化:
public int findComplement(int num) {
int tmp = num, sum = 1;
while(tmp > 0) {
sum = sum << 1;
tmp = tmp >> 1;
}
return sum - 1 - num;
}
省去了求bits的过程,直接在while中完成左移。
但是看别人的答案的时候,发现了另一种求和的思路:
public int findComplement(int num) {
int n = 0;
while (n < num) {
n = (n << 1) | 1;
}
return n - num;
}
那么循环的终止条件为啥那么怪异呢?
我们看n的变化趋势,就是不停的在末位添加一个1,那么n的位数早晚会和原数相等,而和原数位数相等的所有数中,最大的那个肯定是所有位都是1的,原数肯定小于等于此时的n,即n >= num。所以终止条件设为n < num,也就是当n >= num时,n已经是我们想要的那个数了,n不能再增长了。
这个方法中的while循环真的很经典,有好多指的细细品味的地方,它告诉我们,11111这种二进制串是怎么通过位运算造出来的。
补充:
鉴于和的特殊性,这里求补数也可以用异或运算代替减法:
return n ^ num;