您的位置:首页 > 职场人生

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

2014-04-25 14:28 330 查看
在上一篇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;
}
}

总结,对于一个问题,可能有很多种方式来解决,在此过程中需要多动脑筋,最重要的还是解决问题的思路和理解与之关联的知识点,这样才能不断进步。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息