题目:输入一个数(不管是几进制),输出这个数二进制表示中1的个数。比如输入 9 应该输出 2 ;输入0x1F(31) 应该输出 5 。(16进制表示是在前面加 0x )
方案一:
我最开始的想法是把这个数转化成二进制,因为之前做过十进制转二进制所以理所应当的这么想了,最后感觉不太对,要这么写那的写几个进制转换类啊,而且效率不高。
方案二:
然后看了一下书,书上的做法很巧妙:先查看目标数字末尾位是0还是1,这可以通过与一个1做与运算得到结果,然后把目标数字右移一位,继续与1做与,声明一个计数器count,持续加就好。
不过也给出了缺陷,缺陷在于如果目标数字是负数(负数的符号位也要算进总的1的个数里)不光没法的到正确结果,还会让陷入死循环:把负数0x8000右移一位,其实是变成了0xc000,多移几次就变成0xffff然后
死循环了,因为左移和右移是基于这样的原则:
左移时最左边的n位被丢弃,同时在最右边补上n个0。
右移时如果是正数补0,负数在最左边补1.
所以更新方案:把1左移,循环一次就左移一次,这样目标数每一位的1就都不会放过,与运算每得到一个1就count++。反正最后1移到最后就溢出了变成0000000000,这就是循环中止条件。
代码如下:
public class Jianzhi{
public static void main(String[] args){
int num = 0xFF ; //相当于int num = 31 ;
int flag = 1 ;
int count = 0 ;
while( flag != 0 ){
if( (num&flag) != 0 ){
count++ ;
}
flag = flag << 1 ;
}
System.out.print(count);
}
}
这个解法中循环次数等于目标整数二进制的位数,32位整数就需要循环32次,方案三给出目标整数中有几个1就只循环几次的方案。
方案三:
如果一个整数不为0,那么这个整数至少有一位是1。如果我们把这个整数减1,那么原来处在整数最右边的1就会变为0,原来在1后面的所有的0都会变成1(如果最右边的1后面还有0的话)。其余所有位将不会受到影响。
举个例子:一个二进制数1100,从右边数起第三位是处于最右边的一个1。减去1后,第三位变成0,它后面的两位0变成了1,而前面的1保持不变,因此得到的结果是1011.我们发现减1的结果是把最右边的一个1开始的所有位都取反了。这个时候如果我们再把原来的整数和减去1之后的结果做与运算,从原来整数最右边一个1那一位开始所有位都会变成0。如1100&1011=1000.也就是说,把一个整数减去1,再和原整数做与运算,会把该整数最右边一个1变成0.那么一个整数的二进制有多少个1,就可以进行多少次这样的操作。
基于这种思想有如下代码:
public class Jianzhi{
public static void main(String[] args){
int num = 0xFF ; //相当于int num = 31 ;
int flag = num-1 ;
int count = 0 ;
while(num != 0 ){
num = num & flag ;
flag = num - 1 ;
count ++ ;
}
System.out.print(count);
}
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。