编程之美之二进制数中1的个数

问题:

对于一个字节(8bit)的变量,求其二进制中1的个数,要求算法的执行效率尽可能的高。

例如把9表示成二进制是1001,有2位是1,因此如果输入9,1的个数为2。

解法一:

可以举一个8位二进制的例子。对于二进制操纵,我们除以一个2,原来数字就会减少一个0(向右移一位)。如果除的过程中有余,那么久表示当前位置有一个1。

以10100010为例:

第一次除以2时,商为1010001,余为0

第二次除以2时,商为101000,余为1

因此,考虑利用整形数据除法的特点,通过相除和判断余数的值进行分析。

[cpp] view
plain
copy

  1. int Count(int a)  
  2. {  
  3.     int count = 0;  
  4.     while(a)  
  5.     {  
  6.          if(a % 2 == 1)  
  7.          {  
  8.               count++;    
  9.          }  
  10.          a = a / 2;  
  11.     }  
  12.     return count;  
  13. }  

解法二:位操作

使用位操作同样达到相除的目的。

使用与操作(&)来判断最后一位是不是1,判断完后向右移一位,继续判断。

可以把这个八位数与00000001进行与操作,如果结果为1则表示这个八位数最后一位为1,否则为0。

[cpp] view
plain
copy

  1. int Count(int a)  
  2. {  
  3.     int count = 0;  
  4.     while(a)  
  5.     {  
  6.          count += a & 0x01;  
  7.          a >>= 1;  
  8.     }  
  9.     return count;  
  10. }  

位操作要比除法取余操作效率要高许多。

解法三:

作者用到一个巧妙的方法,自己与自己减1相与,(例:10100010 & 10100001 = 10100000)从而到达消去最后一位1,通过统计循环次数达到计算1的个数的目的,这个方法减少了一定的循环次数。

具体解析看看原著。

[cpp] view
plain
copy

  1. int Count(int a)  
  2. {  
  3.     int count = 0;  
  4.     while(a)  
  5.     {  
  6.         a = a & (a-1);  
  7.         count++;  
  8.     }  
  9.     return count;  
  10. }  

解法四:分支操作

解法三的复杂度降到O(M). 其中M为1的个数。这效率已经足够高了。

如果还不满足,还有一种方法。既然才是一个8位的数据(0~255),可以直接0~255的情况罗列出来,使用分支操作,得到答案。

这个方法看似很直接,但是效率可能会比其他方法要低。具体情况具体分析。如果a = 0比较一次就会得到答案,但是a = 255比较255次才得到答案

[cpp] view
plain
copy

  1. int Count(int a)  
  2. {  
  3.     int count = 0;  
  4.     switch(a)  
  5.     {  
  6.         case 0x0:  
  7.              count = 0;  
  8.              break;  
  9.         case 0x1:  
  10.         case 0x2:  
  11.         case 0x4:  
  12.         case 0x8:  
  13.         case 0x10:  
  14.         case 0x20:  
  15.         case 0x40:  
  16.         case 0x80:  
  17.              count = 1;  
  18.              break;  
  19.         case 0x3:  
  20.         case 0x6:  
  21.         case 0xc:  
  22.         case 0x18:  
  23.         case 0x30:  
  24.         case 0x60:  
  25.         case 0xc0:  
  26.              count = 2;  
  27.              break;   
  28.         //.....  
  29.     }  
  30.     return count;  
  31. }  

解法五:查表法

直接把0~255相应1的个数直接存在数组中,采取以空间换取时间。

[cpp] view
plain
copy

  1. int CountTable[256] =       
  2. {          
  3.          0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,  
  4.          1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,  
  5.          1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,  
  6.          2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,  
  7.          1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,  
  8.          2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,  
  9.          2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,  
  10.          3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,  
  11.          1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,  
  12.          2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,  
  13.          2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,  
  14.          3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,  
  15.          2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,  
  16.          3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,  
  17.          3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,  
  18.          4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8          
  19. };  
  20.   
  21. int Count(int a)  
  22. {  
  23.     return CountTable[a];  
  24. }  
时间: 2024-11-02 21:56:53

编程之美之二进制数中1的个数的相关文章

Java数据结构及算法实例:快速计算二进制数中1的个数(Fast Bit Counting)_java

/** * 快速计算二进制数中1的个数(Fast Bit Counting) * 该算法的思想如下: * 每次将该数与该数减一后的数值相与,从而将最右边的一位1消掉 * 直到该数为0 * 中间循环的次数即为其中1的个数 * 例如给定"10100",减一后为"10011",相与为"10000",这样就消掉最右边的1 * Sparse Ones and Dense Ones were first described by Peter Wegner i

[华为机试练习题]45.求某二进制数中1的个数

题目 描述: 题目标题: 求某二进制数中1的个数. 给定一个unsigned int型的正整数,求其二进制表示中"1"的个数,要求算法的执行效率尽可能地高. 详细描述: 原型: int GetCount(unsigned int num) 输入参数: num 给定的正整数 输出参数(指针指向的内存区域保证有效): 无 返回值: 返回1的个数 举例: 输入13,则对应的二进制是1101,那么1的个数为3个.则:返回3. 练习阶段: 初级 代码 /*--------------------

编程之美之字符串移位包含问题

[题目] 给定两个字符串s1和s2,要求判断s2是否能够被通过s1做循环移位(rotate)得到的字符串包含.例如,S1=AABCD和s2=CDAA,返回true:给定s1=ABCD和s2=ACBD,返回false. [分析] [思路一] 从题目中可以看出,我们可以使用最直接的方法对S1进行循环移动,再进行字符串包含的判断,从而遍历其所有的可能性. 字符串循环移动,时间复杂度为O(n),字符串包含判断,采用普通的方法,时间复杂度为O(n*m),总体复杂度为O(n*n*m). 字符串包含判断,若采

2013编程之美资格赛总结

终于可以完成一个程序比赛的题目了,虽然这次的时间有些长.这是第一次完成,感到真心不错.参加程序比赛是受舍友的影响,但很快就喜欢上了.但,从前不见第一次参加程序比赛--腾讯的编程马拉松,一个题不会,连提交代码的心思都没有.到第二次,参加百度的百度之星,百度之星参加了两次区域赛,第一次做的唯一一道题连题意都没有明白,结果不言而喻,失败:第二次区域赛,明白了题意,写出来代码,但提交结果还是失败,因为没有对于大数据进行思考.这就是参加的两次比赛的情况.这是第三次参加,是微软的编程之美,依据现在的结果,感

微软编程之美挑战赛的冠军

在第二届微软"编程之美全国挑战赛"总决赛中,冠军是一名来自北京邮电大学的大三女生,她的名字叫李雪,今年21岁.本次决赛最大的不同之处就在于,这是 在微软的云平台Windows Azure上进行的.在云平台上展开竞赛,这让很多在校大学生提前接受了云计算的"洗礼".     本届的"编程之美全国挑战赛"一共吸引了13000多名来自全国40多所高校的优秀学子报名参加,其中不乏来自清华.北大.上交大等以计算机专业而闻名的顶尖院校的学生.万人竞技,竞争的激

编程之美之2.14 求数组的子数组之和的最大值

[题目] 一个有N个整数元素的一维数组(A[0],A[1],A[2],...A[n-1]),这个数组中当然有很多子数组,那么子数组之和的最大值是多少? 该子数组是连续的. 我们先来明确一下题意: (1)子数组意味着是连续的. (2)题目只需要求和,并不需要返回子数组的具体位置. (3)数组的元素是整数,所以数组可能包含正整数,负整数或者零. 举几个例子: 数组:[1,-2,3,5,-3,2]返回8  数组:[0,-2,3,5,-1,2]返回9 数组:[-9,-2,-3,-5,-3]返回8 [解法

2013编程之美资格赛之长方形(Java实现)

长方形 时间限制: 1000ms 内存限制: 256MB 描述 在 N 条水平线与 M 条竖直线构成的网格中,放 K 枚石子,每个石子都只能放在网格的交叉点上.问在最优的摆放方式下,最多能找到多少四边平行于坐标轴的长方形,它的四个角上都恰好放着一枚石子. 输入 输入文件包含多组测试数据. 第一行,给出一个整数T,为数据组数.接下来依次给出每组测试数据. 每组数据为三个用空格隔开的整数 N,M,K. 输出 对于每组测试数据,输出一行"Case #X: Y",其中X表示测试数据编号,Y表示

图书推荐:《编程之美——微软技术面试心得》

问题描述 想知道微软面人的内幕吗?--<编程之美--微软技术面试心得>通过分析微软面试中经常出现的题目,给您解答微软面试疑惑.写程序真的没有意思?为什么许多微软的员工乐此不疲?--<编程之美--微软技术面试心得>将告诉您:编程和生活一样是富于激情和艺术性的!<编程之美>一书中包含了约60道算法和程序设计的题目,是微软的工程师写的.这些题目大部分在近年的笔试,面试中出现过,或者是被微软员工热烈讨论过.作者试图从书中各种有趣的问题出发,引导读者发现问题,分析问题,解决问题,

2013编程之美资格赛之树上的三角形(Java实现)

树上的三角形 时间限制: 2000ms 内存限制: 256MB 描述 有一棵树,树上有只毛毛虫.它在这棵树上生活了很久,对它的构造了如指掌.所以它在树上从来都是走最短路,不会绕路.它还还特别喜欢三角形,所以当它在树上爬来爬去的时候总会在想,如果把刚才爬过的那几根树枝/树干锯下来,能不能从中选三根出来拼成一个三角形呢? 输入 输入数据的第一行包含一个整数 T,表示数据组数. 接下来有 T 组数据,每组数据中: 第一行包含一个整数 N,表示树上节点的个数(从 1 到 N 标号). 接下来的 N-1