二进制中1的个数
题目:
输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。
思路:
1.无符号位右移
无符号右移:是因为当为负数的时候,因为负数的最高位即符号位为1,这样最高位补0,才不会死循环。
public static int NumberOf1(int n) {
int count = 0;
while(n != 0){
if((n & 1) == 1) {
count++;
}
n >>>= 1;
}
return count;
}
2.左移1
除了移动这个数之外也可以移动左移1 可以起到同样的作用,只需要左移32位,因为int 32位。
// 移动辅助变量 1 左移一位
public static int NumberOf1(int n) {
int count = 0;
int flag = 1;
for (int i = 0; i < 32; i++) {
if ((n & flag) != 0) {
count++;
}
flag <<= 1;
}
return count;
}
3. 位操作运算
以上二种做法都是按位扫描,复杂度为O(n)。有没有最好的方法呢?当然有。我们首先把原数做减一操作,看2种情况(数不为0的情况下):
- 当最后一位是1,减去1后,该位置为0,其余位置保持不变。比如7(111) - 1 = 6(110)
- 当最后一位不是1,假设第m位为该数二进制的最右边的1,减去1后,第m位变为0,但是第m位之后直到末尾全部变了1。比如12(1100)- 1 = 11 (1011)。
通过上面发现,对原数做减一操作,都可以使数的最右边的1变为0。如果是第一情况,该数其他位置不变,但是如果是第二情况,则会导致m位之后变为1,那如何使m位之后还是以前的0呢,做与操作。原数与减一后的数做与操作。即可做到m位之前不变,m位之后也与原数相同(即都为0)。
结论为:把一个整数减去1后与原数做与操作,得到的结果为整数的二进制形式的最右边的一个1变为0。
所以如果原数有n个1,我们只需进行n次这样的减一和与操作即可了。Amazing!
//1. 位操作运算 n &= n-1
public int NumberOf1(int n) {
int count = 0;
while(n != 0){
n &= n - 1;
count++;
}
return count;
}
310

被折叠的 条评论
为什么被折叠?



