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

5 篇文章 0 订阅
5 篇文章 0 订阅

在上一篇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;
	}
 }

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值