博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
算法题之一(数字二进制形式中1的个数)
阅读量:4362 次
发布时间:2019-06-07

本文共 1886 字,大约阅读时间需要 6 分钟。

题目:请实现一个函数,属于一个整数,输出该数二进制表示中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 }

 

转载于:https://www.cnblogs.com/wanxiao1994/p/3807147.html

你可能感兴趣的文章
linux-nohup命令
查看>>
[LeetCode OJ] Roman to Integer
查看>>
三次握手和四次挥手
查看>>
Redis的简单动态字符串实现
查看>>
putty network error:software caused connection abort
查看>>
存储过程 <3> 和函数的区别
查看>>
高级service之ipc ADIL用法
查看>>
Django框架-基础篇
查看>>
Leetcode: Binary Tree Maximum Path Sum
查看>>
通过虚拟环境创建并开始一个django
查看>>
关于 input[type="button"] , button
查看>>
Android ViewDragHelper全然解析 自己定义ViewGroup神器
查看>>
c++ 基础 const char* 转 char*
查看>>
JS-- 小细节--你悟到了什么?
查看>>
收款 借贷
查看>>
Gson关于抽象类的序列化与反序列化
查看>>
Java面向对象之类和对象
查看>>
Oracle数据库提权(dba权限执行系统命令)
查看>>
Hydra爆破神器使用
查看>>
java.util.zip.ZipException: duplicate entry(重复依赖多版本的类库)
查看>>