题目描述
输入一个整数,输出该数32位二进制表示中1的个数。其中负数用补码表示。
解题思路:四种方法。第一种对于负数是不可行的,其他三种可行。
第一种方法是模拟二进制的移位,每次循环将整数对2取余,如果不为0,代表最后一位为1,则ans++,否则最后一位为0,直接将整数除以2,类似于二进制移位操作。但是这种方法有一个弊端,就是对于int类型所能取到的最小负数,即-Integer.MAX_VALUE,没办法正确处理。
解释如下,因为int型的最小负数,换成二进制是10000....(31个0),但是在计算机中是按照补码的形式存储的,所以第一个符号位不改变,其他位取反,之后+1,得到补码为000000...(32个0)。使用这种方法是按照计算机中的补码形式计算的,因此输出的是0,而不是1,算法有漏洞。代码不写了,都很简单。
其他三种方法都是大同小异了,按照位运算进行处理,还是要注意负数的移位操作,右移时,对于负数,低位舍去,为了维护负数的表现形式,高位是需要补1的,所以也会对结果造成影响。
因此,自己的想法是,使用java中的无符号移位运算符,对整数n进行无符号移位,即向右移位时,高位补0,这样涵盖了负数在内的所有情况,代码如下:
public class Solution {
public int NumberOf1(int n) {
int ans = 0;
while (n != 0) {
if((n&0x01) != 0) // 这里特别要注意的是使用&运算符时需要将两个运算的对象用括号包起来,不然会报错误
ans ++ ;
n>>>=1 ;
}
return ans ;
}
}
第三种,就是不让整数n进行移位操作,而是令一个二进制数,0x01依次向左移位,如果与整数n取与操作,结果不为0,代表整数n当前位置为1,ans++。代码没写,粘贴一下:
int val; // input data
int ans = 0;
int mark = 0x01;
while (mark != 0) {
if (mark & val) ++ans;
mark <<= 1;
}
第四种,举例说明:二进制数a = 1101100,
(a-1) = 1101011,因此将整数依次和整数-1的值取与操作,得到的是
a&(a-1) =1101000 ,每计算一次,更新整数的值并且ans++。当整数==0时,代表所有的1都已被记录。
代码如下:
public class Solution {
public int NumberOf1(int n) {
int ans = 0;
while (n != 0) {
ans ++ ;
n = n&(n-1) ;
}
return ans ;
}
}
本文介绍了一种算法,用于计算输入整数32位二进制表示中1的个数,包括四种不同的实现方法:模拟二进制移位、无符号移位、位标记扫描和位清除技术。

2042

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



