二进制中一的个数

题目:输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。右移一位

首先我们第一个想到的是将该整数和1做&运算如果等于1则计数加1,然后右移,直到右移后该数为0为止

代码实现:

public int NumberOf1(int n) {
		int count=0;
		while(n!=0)
		{if((n&1)==1) 
		 {
			count++;
		 }
		  n=n>>1;//不选除法运算而选择移位运算是因为移位运算比除法运算效率高
		}
		return count;
	}

这种解法存在一个缺陷就是,当输入负数时,会引起死循环。因为负数在做移位运算的时候计算机为了保证该数还是一个负数,他会在前面补一个一。例如:负数1101做移位运算后是1110

那么怎么避免死循环呢?我们可以把移位对象换成1,也就是每循环一次之后我们就把1左移一位,如果1个输入的整数相$不等于0,那么说明整数二进制对应的1所在的位置处是1,当移到0时循环结束,也就是1溢出了.

例如:输入一个整数6那么他的二进制就是00000000 00000000 00000000 00000110,开始1和00000000 00000000 00000000 00000110做&运算(其实就是和00000000 00000000 00000000 00000110的最后一位做&)得到的是0,接着把1左移得10,将得到的10和00000000 00000000 00000000 00000110做&运算(其实就是和00000000 00000000 00000000 00000110的倒数第二位做&)得到10,以此类推最后1被移位成1 00000000 00000000 00000000 00000000,将1舍去了(超过了32位)实现的代码如下

代码:


	public int NumberOf1(int n) {
		int count = 0;
		int flag = 1;
		while (flag != 0) {
			System.out.println(n&flag);
			if ((n & flag) != 0) {
				count++;
			}
			flag = flag << 1;
		}
		return count;
	}

这种方法也不是最优解,因为他需要1移位32次,所以我们需要想出一种办法,让他循环最少。

我们来思考一下如果将一个数减去1,它的二级制会变成什么

整数14,二进制1110

14-1,二进制1101

整数15,二进制1111

15-1,二进制1110

从上面我们可以总结出当最后一位为0时,将该数减1,它最后一个1就变成了0,最后一位1的后边的所有0变成了1.

当最后一位是1时,该数的最后一位变为0,前边所有都不变。

那么我们怎么利用这个来计算出有多少个1呢?

道理很简单我们逐个屏蔽掉最后一个1,屏蔽了多少次,就有多少个1。

举个栗子:1111-1 = 1110 

接下来我们只需要算1110有多少个1就好了,那么怎么得到1110呢?

我们思考一下将1111和1110做&得到了什么

答案是1110

这样问题就解决了,让我们再顺一下思路。

思路:将输入的整数n与n-1做&运算,将结果赋给n,就是n=n&(n-1)直到n=0结束,能做几次就有几个1。

最优代码:

	 public int NumberOf1(int n) {
	 int count=0;
	 while(n!=0)
	 {
	 ++count;
	 n=(n-1)&n;
	
	 }
	 return count;

	 }



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值