面试题-求一个数的二进制数中1的个数(2)

来源:互联网 发布:九宫图算法彩票 编辑:程序博客网 时间:2024/06/01 20:41

在上一篇blog文中,求一个数的二进制数中1的个数,我使用了一个比较复杂的方式来解决这个问题,

这里非常感谢reality_jie同学指出来的可以改进的地方,这道题在编程之美中出现过,主要考查的是位运算。
对于一个数,其实主要从第一位开始判断,如果是1则出现1的个数加一,判断方式是和1作与运算,如果第一位是1,那么结果会得到1,其他情况得到的是0,然后这个数右移1位,继续进行判断,直到这个数为0为止,具体代码如下:

/*程序来源:腾讯面试题 * 源文件名称:NumToBin3.java *要  点: *输入一个数,输出它二进制中1的个数 */  public class NumToBin3{public static void main(String[] args){System.out.println(numToBin3(1));System.out.println(numToBin3(5));System.out.println(numToBin3(10));}static int numToBin3(int num){int flag = 0;while(num>0){if((num&1) ==1 ){flag++;}num = num>>1;}return flag;} }

但是考虑下这种情况,如果num是个负数怎么办,上面的方式是判断num>0,无法计算负数,如果改成判断条件为num!=0,那么会造成死循环,为什么呢

1.首先对于左移运算符<<来说,规则只要记住:丢弃最高位,0补最低位。也就是说在左移的过程中,假设一个int类型的数有32位,最高位是符号位,那么在左移的时候,如果最高位变成1,那么这个数就变成了负数,举个例子,0x 0F FF FF FF,原来最高位是0,是个正数,那么向左移动4位,变成0xFF FF FF F0,最高位变成了1,就变成了负数。

2.对于右移运算符>>,记住一点:符号位不变,左边补上符号位。运算规则是,按二进制的形式把数字向右移动对应的位数,符号位不变,其他位置移动,高位的空位补上符号位,即正数补0,负数补1,低位移出。举个例子,0xFF FF FF F0这个数,向右移动4位,那么由于符号位是1,所以在右移动的过程中,出现空位的地方补上1,所以得到

0xFF FF FF FF,结果应该是-1,可以看下程序:

public class Test{public static void main(String[] args){int i = 0xfffffff0;System.out.println(i>>4);}} 

运行结果:


3.还有一种运算符,叫做无符号右移>>>,规则只记住一点:忽略了符号位扩展,0补最高位,其实跟左移是相似的,但是只对32为和64位的运算符有意义。

最后还有一点要注意的是:如果移动的位数超过了该类型的最大位数,那么编译器会对移动的位数取模,假设对一个int型的数移动33位,那么对其取模,33%32 = 1,实际上只移动了一位。

回到之前的问题,如果要求一个数,无论正负,它的二进制数中包含的1的个数,我们只需要对之前的程序稍微改进一下,就可以了:

/*程序来源:腾讯面试题 * 源文件名称:NumToBin3.java *要  点: *输入一个数,输出它二进制中1的个数 */  public class NumToBin3{public static void main(String[] args){System.out.println(numToBin3(-1));System.out.println(numToBin3(5));System.out.println(numToBin3(10));}static int numToBin3(int num){int flag = 0;while(num!=0){//这里判断条件是当num=0的时候才结束if((num&1) ==1 ){flag++;}num = num>>>1; //这里使用无符号右移运算符,就不用担心右移符号位扩展问题}return flag;} }

运行结果如下:


还有一种方式,是要判断的数不动,然后1左移,每次移动一位,然后和这个数做与运算,如果对应的位置上为1,则运算结果是i,那么这个数含有的1的个数加1:

/*程序来源:腾讯面试题 * 源文件名称:NumToBin4.java *要  点: *输入一个数,输出它二进制中1的个数 */  public class NumToBin4{public static void main(String[] args){System.out.println(numToBin4(-1));System.out.println(numToBin4(5));System.out.println(numToBin4(10));}static int numToBin4(int num){int flag = 0;int i = 1;while(i!=0){if((num&i) == i){flag++;}i = i<<1; }return flag;} }

总结,对于一个问题,可能有很多种方式来解决,在此过程中需要多动脑筋,最重要的还是解决问题的思路和理解与之关联的知识点,这样才能不断进步。

0 0