每天一道算法题:数字二进制形式中1的个数

题目:请实现一个函数,属于一个整数,输出该数二进制表示中1的个数,例如把9表示成二进制是1001,有2位为1。因此如果输入9,该函数输出2。

  • 可能的死循环陷阱

    看完题目,相信大家很快就能想到一个解题思路:先判断整数二进制表示中最右边的一位是否为1,接着把输入的整数右移一位,此时原来处于从右边起的第二位被移动至最右边了,再判断是不是1,这样每次移动一位,直到这个整数变成0,即能够得到整数二进制表示形式中1的个数,而现在问题变为如何判断数字的最后一位为1,其实这个也很简单,只需要将数字与1做与运算,如果结果为1,则表示最后一位为1,否则为0。有了上面的思路,我们很快能写出如下的代码:

 1 int NumberOf1(int number)
 2 {
 3     int count = 0;
 4
 5     while (0 != number)
 6     {
 7         if (0 != (number & 0x01))
 8         {
 9             ++count;
10         }
11
12         number = number >> 1;
13     }
14
15     return count;
16 }

  作为一个严谨的程序猿,写完代码必须要对代码进行相应的测试,当我们输入正整数时,程序能够正确运行,但是当我们输入负整数时,程序好像不能停止了,为什么会这样?当我们再回头去看代码,并看到number = number >> 1时,才恍然大悟,因为负数带有符号位,而在进行右移操作时,由于要保持其任然为负数,会在左边的第一位补1而不是0,这样一直进行以为,最终整数变为了0XFFFFFFFF,而陷入死循环。如何避免该问题呢?

  • 常规解法

  当上面的问题出现时,我们想到,既然不能将整数向右移动,那我们为什么不将1向左边移位后再与输入整数进行与运算呢?这样的处理方式能达到同样的效果,并且左移永远都只会在右边的位置补0,这样就避免了死循环的出现,好了,有了这样的思路我们又写出下面的第二个版本代码:

 1 int NumberOf1(int number)
 2 {
 3     int count = 0;
 4     int flag = 0x01;
 5
 6     while (0 != flag)
 7     {
 8         if (0 != (number & flag))
 9         {
10             ++count;
11         }
12
13         flag = flag << 1;
14     }
15
16     return count;
17 }

  当完成代码之后,进行测试都能得到正确的结果,似乎已经是完美答案了,but,我们发现不管我们输入的整数二进制形式中有几个1,我们的程序都将循环32次才能得到结果,有没有什么方法能够使我们的循环次数更少呢?比如二进制中有几个1就只循环几次的方法,答案是肯定的,请接着往下看。

  • 惊艳的解法

    再分析算法之前,我们先来分析把一个整数减1的情况,如果一个整数不等于0,那么该整数的二进制表示中至少有1位是1,先假设这个数的最后一位是1,将该整数减1之后,最后一位变为0,其他位保持不变,接下来假设最后一位不是1而是0的情况,如果该数最右边的1位于第m位,则将此数减1之后,该数的第m位由1变为0,而m位之后的所有位都由0变为1,第m位之前的位都保持不变,如果再将该整数与该整数减1之后的结果进行与运算,其效果相当于把整数最右边为1的位由1变为0。我们把上面的分析总结起来就是:把一个整数减1之后再与整数本身做与运算,会把整数二进制形式中最右边的一个1变成0,那么一个整数的二进制形式中存在多少个1,我们就可以对该整数做几次上述的操作,有了上面的思路,我们能写出新的解法:

 1 int NumberOf1(int number)
 2 {
 3     int count = 0;
 4
 5     while (0 != number)
 6     {
 7         ++count;
 8
 9         number = number & (number - 1);
10     }
11
12     return count;
13 }

每天一道算法题:数字二进制形式中1的个数,布布扣,bubuko.com

时间: 2024-10-01 06:44:00

每天一道算法题:数字二进制形式中1的个数的相关文章

统计整型数据二进制形式中1的个数

统计整型数据二进制形式中1的个数可以通过如下方式达到: int cnt1bits(int x) { int count = 0; while (x) { ++count; x = x & (x - 1); } return count; }

算法题:求二进制位中0的个数

#include <iostream> using namespace std; //古有求二进制数中1的个数,今有求二进制中0的个数. int Grial(int x) { int count = 0; while (x + 1) { count++; x |= (x + 1); } return count; } int main() { cout << Grial(1) << endl; return 0; } //为了方便验证,我把求二进制数中1的个数也写下来.

算法——一天一道算法题篇——找只出现一次的两个数

找只出现一次的两个数 题目: 一个整型数组里除了两个数字只出现一次之外,其他的数字都出现了两次.请写程序找出这两个只出现一次的数字. 举例说明: 现在有一个数组:{1,3,4,2,4,3}; 假设数组元素的规模不是很大,想要找到只出现一次的元素,可以定义一个辅助数组,flag[100];里面存放的是数组元素出现的次数,flag数组的下标表示的是数组:{1,3,4,2,4,3}里的元素. 代码如下: package hello.ant; public class AlogArrayFind2 {

一天一道算法题--6.25--无定义

感谢微信平台---一天一道算法题--每天多一点进步---- 其实今天我接下去补上的几题都来自---待字闺中 所以我就原封不动的将它的题目与分析搬过来了 原题 给定一个数组,我们可以找到两个不相交的.并且是连续的子数组A和B,A中的数字和为sum(A), B中的元素和为sum(B).找到这样的A和B,满足sum(A) - sum(B)的绝对值是最大的. 例如:[2, -1 -2, 1, -4, 2, 8]划分为A=[-1, -2, 1, -4], B=[2, 8], 最大的值为16 分析 如果没有

前端面试的一道算法题

(使用canvas解答) 下面说一个跟前端有点相关并且有点趣的一道算法题. 题目: 平面上有若干个不特定的形状,如下图所示.请写程序求出物体的个数,以及每个不同物体的面积. 分析 想要知道有多少个图形,想到的就是先获取图片中的每一个像素点然后判获取像素点的背景颜色(RGBA).想要获得图片中的每一个像素点,那就可以联想到使用h5的canvas.如下: 菜鸟教程中canvas的getimagedata方法http://www.runoob.com/tags/canvas-getimagedata.

一天一道算法题--6.19--二分搜索

感谢微信平台---一天一道算法题---每天多一点进步 这是昨天的 只贴下题目 == 再把今天的也是一样处理了   这2天 不想写 可能晚上会有改变吧.. problem: 给定一个最多包含40亿个随机排列的32位 二进制的无符号整数 找出不在文件中的数.显然 由于 2^32=4294967196大于4亿 所以缺少的数不止一个 现限制只能使用几个外部的临时文件和仅几百个字节的内存. ****************************** 过了明天 就没事了 =-= 一天一道算法题--6.19

一天一道算法题--5.25--bfs或者最短路

好吧 还是拖到了5.26来写本是5.25的题... 自我 宽恕 老样子---  感谢    微信平台: 一天一道算法题   无聊的你 也可以去关注一下 题目 链接:http://poj.org/problem?id=3126 题目 大意:  给你2个素数 问从一个素数到另一个转换的过程中  每次只允许改变一个位上的数 并且在改动过程中 保证它也是素数  最少需要多少次实现这个转换? ok 其实 这题 不算难  当告诉你这是个搜索以后  只是在进行个位 十位 百位 千位 上各个数字尝试的时候 可能

一天一道算法题---6.26---二分查找

感谢微信平台---一天一道算法题----每天多一点进步-- 好累啊  现在在用win7自带的输入法 打起来真麻烦 快点把这2天的搞完就重装了 还是直接来源于----〉 待字闺中 分析 给定一个数组A,其中有一个位置被称为Magic Index,含义是:如果i是Magic Index,则A[i] = i.假设A中的元素递增有序.且不重复,请给出方法,找到这个Magic Index.更进一步,当A中允许有重复的元素,该怎么办呢? 没有重复元素的情况 一些同学在遇到这个题目的时候,往往会觉得比较简单.

一天一道算法题---6.27---二分图

感谢微信平台---一天一道算法题---每天多一点进步--- Ah... last... 也很晚了 快2点半了 C罗也告别这届世界杯了  主要还是输给德国太多球了 美国也没赢 唉 还是来源于----> 待字闺中 原题 大家都知道facebook用户都是双向的好友,a是b的好友,那么b一定是a的好友,现在给定一个用户列表,其中有些用户是好友,有些不是,请判断,这些用户是否可以划分为两组,并且每组内的用户,互相都不是好友.如果能,请给出这个划分. 例子1: 用户:{1, 2, 3} 好友关系:1-2,