题目:输入一个数(无论是几进制),输出这个数二进制表示中1的个数。好比输入 9 应该输出 2 ;输入0x1F(31) 应该输出 5 。(16进制表示是在前面加 0x )code
方案一:class
我最开始的想法是把这个数转化成二进制,由于以前作过十进制转二进制因此理所应当的这么想了,最后感受不太对,要这么写那的写几个进制转换类啊,并且效率不高。
方案二:效率
而后看了一下书,书上的作法很巧妙:先查看目标数字末尾位是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,就能够进行多少次这样的操做。static
基于这种思想有以下代码:while
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); } }