输入一个十进制整数,统计其中二进制1的个数

[java]  view plain  copy
  1.   
题目:统计给定的十进制数的二进制中1的个数

分析:

1.很多人看到这个需求的时候,第一反应是先把给定的十进制数转换成二进制数,再把二进制数转换为字符数组,再遍历这个字符数组计算1出现的次数,但是存在一些问题,首先在没有Java相关类库使用的情况下,十进制转换为二进制这个过程应该是很复杂的,并且如果最求算法效率的话,对于数组所需的额外空间以及循环遍历的n次比较的开销是我们所希望避免的。

2.然后我们有相关经验的程序员应该可以想到,既然涉及到了二进制的问题,那么必然少不了Java中的位运算,自然而然地想到了&、|、>>等相关运算符,于是,很多人想到了如下解题方法:

[java]  view plain  copy
  1. public static int getNumber(int n){  
  2.         int count = 0;  
  3.         while(n!=0){  
  4.             if((n&1)==1){  
  5.                 count++;  
  6.             }  
  7.             //将n右移一位  
  8.             n = n>>1;  
  9.         }  
  10.         return count;  
  11.     }  
二进制数与1进行与运算,如果结果得到1说明,该二进制数的最低位为1,则计数加1,然后让n向右移1位,,然后再与1进行与运算。最后美滋滋地得到二进制中1出现的次数。

但是:上述的代码忽略了一个致命的问题,就是如果给定的整数位负数,在该数右移操作的时候,高位补的是1,而不是0,逐渐32位的数都会变成1,那么进行与运算就永远得到是1,那么就变成了死循环。

3.在第2步中,总体的思路已经没问题了,那么如何解决上面所出现的问题呢?我们想到位运算中,右移运算与数的正负有关,但是左移运算与数的正负并没有关系,我们可以用到左移运算,这次我们不让给定的整数进行位移运算,我们让1进行左移运算,然后再与给定整数的二进制数进行与运算,这样,就完美解决了整数正负的问题

实现代码如下:

[java]  view plain  copy
  1. public static int getNumber2(int n){  
  2.         int count = 0;  
  3.         //这是需要进行左移运算的1,其二进制数为  
  4.         //0000 0000 0000 0000 0000 0000 0000 0001  
  5.         int target = 1;  
  6.         //如果1左移到最左端,所得得为 0000 0000 0000 0000 0000 0000 0000 0000 为0,则跳出循环  
  7.         while(target !=1){  
  8.             if((n&target) !=0){  
  9.                 count++;  
  10.             }  
  11.             //左移运算  
  12.             target = target<<1;  
  13.         }  
  14.         return count;  
  15.     }  


4.除了3中的解题方法外,再介绍一种更为高效的方法

如果将一个二进制数-1,那么该二进制数最右侧的1将会变成0,1后面的0均变成1,1前面的数保持不变

也就是说,如果把一个二进制数-1,那么概述最右侧的1及1右侧的所有书将改变(0-->1或者1--->0)

如果把这个数和原数进行与运算,那么最右侧的那个1前面的1将不变,1以及1右侧的所有书将变成0,也就是说进行一次上述运算后,原数最右侧的那个1会变成0,那么只要重复上述操作,当原数变成0时,循环就是1的个数


实现代码

[java]  view plain  copy
  1. public static int getNumber3(int n){  
  2.         int count =0;  
  3.         while(n!=0){  
  4.             n=n&(n-1);  
  5.             count++;  
  6.         }  
  7.         return count;  
  8.     }  
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值