剑指offer之二进制中1的个数

举报
chenyu 发表于 2021/07/26 23:28:48 2021/07/26
【摘要】 1 问题 实现一个函数,输入一个函数,输出该二进制数据中1的个数。例如9表示二进制数据1001,有2位是1,因此输入9,该函数会输出2。           2 分析 我们先了解下计算机里面位运算,有5种 1)& 这个是与操作,规律如下 1 & 1 = 1 1 & 0 = 0 0 &...

1 问题

实现一个函数,输入一个函数,输出该二进制数据中1的个数。例如9表示二进制数据1001,有2位是1,因此输入9,该函数会输出2。

 

 

 

 

 

2 分析

我们先了解下计算机里面位运算,有5种

1)& 这个是与操作,规律如下

1 & 1 = 1 1 & 0 = 0 0 & 1= 0 0 & 0 = 0
 

2)| 这个是或运算,规律如下

1 | 1 = 1 1 | 0 = 1 0 | 1= 1 0 | 0 = 0
 

3)^ 异或运算,规律如下

1 ^ 1 = 0 1 ^ 0 = 1 0 ^ 1 = 1 0 ^ 0 = 0 
 

4) 左移 m<<n 表示把m左移n位,在左移n位的时候,最左边的n位丢弃,同时右边补上n个0 比如


  
  1. 00001010 << 2 = 00101000
  2. 10001010 << 3 = 01010000

5) 右移 左移 m >> n 表示把m右移n位,在右移n位的时候,最右边补上n个0 ,最左边分2种情况,如果数字是一个无符号整形

则用0填补最左边的n位,如果是一个有符号的数据,则最左边用数字的符号填补n个数据。如果是正数,左边补n个0,是负数左边补n个1.


  
  1. 00001010 >> 2 = 00000010
  2. 10001010 >> 3 = 11110001

 

这里我们可以把原数据和1进行&操作,如果二进制数据尾巴进行&操作,如果包含1的话&1操作就是1,返之结果为0,然后我们把数据进行右移一位就行。

 

如果一个正数要除以2,我们效率最高的是把这个数据进行右移一位。

 

 

 

 

3 代码实现

C++版本


  
  1. #include <stdio.h>
  2. /*
  3. *二进制数据里面包含数字1的个数
  4. */
  5. int containOneNumber(int value)
  6. {
  7. int count = 0;
  8. while (value != 0)
  9. {
  10. //这里是(value & 1)不是(value & 0)
  11. if (value & 1)
  12. ++count;
  13. //这里是value = value >> 1,而不是value >> 1; 我们要用变量接收它
  14. //不然不管就只执行了一次也就是value除以了2,所以导致死循环。
  15. value = value >> 1;
  16. }
  17. return count;
  18. }
  19. int main(void)
  20. {
  21. int result = containOneNumber(9);
  22. printf("result is %d\n", result);
  23. return 0;
  24. }

java版本


  
  1. public int containOneNumber(int value)
  2. {
  3. int count = 0;
  4. while (value != 0)
  5. {
  6. if ((value & 1) != 0)
  7. {
  8. count++;
  9. }
  10. value = value >>> 1; //>>>就是java中的无符号右移
  11. }
  12. return count;
  13. }

我们知道java用 >>> 是无符号右移,右移的时候,所以最高位左边都是0,如果这个数是负数的时候,右移的话最高位会补1,

C++版本就会变成死循环。

 

 

 

 

 

4 优化

方法1:

n与1做与运算,判断n的最低位是不是为1,接着把1左移一位得到2,再和n做与运算,就能判断n的次低位是不是1….这样反复左移


  
  1. int containOneNumber1(int n)
  2. {
  3. int flag = 1;
  4. int count = 0;
  5. while (flag != 0)
  6. {
  7. if ((flag & n) != 0)
  8. {
  9. count++;
  10. }
  11. flag = flag << 1;
  12. }
  13. return count;
  14. }

 

方法2:

把一个整数减去1,再和原整数做与运算,会把该整数最右边一个1变成0,那么一个整数的二进制表示中有
多少个1,就可以进行多少次这样的操作


  
  1. int containOneNumber1(int n)
  2. {
  3. int flag = 1;
  4. int count = 0;
  5. while (n != 0)
  6. {
  7. ++count;
  8. n = n & (n - 1);
  9. }
  10. return count;
  11. }

 

 

 

 

 

5 总结

1) 把一个整数减去1,再和原整数做与运算,会把该整数最右边一个1变成0,那么一个整数的二进制表示中有多少个1

2)n与1做与运算,判断n的最低位是不是为1,接着把1左移一位得到2,再和n做与运算,就能判断n的次低位是不是1….这样反复左移

3) 如果是正整数的情况下,我们可以把正整数右移动和1进行&操作,然后再去统计。

文章来源: chenyu.blog.csdn.net,作者:chen.yu,版权归原作者所有,如需转载,请联系作者。

原文链接:chenyu.blog.csdn.net/article/details/102675036

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。