剑指offer-面试题10:二进制中1的个数

来源:互联网 发布:java项目遇到最大困难 编辑:程序博客网 时间:2024/05/22 08:22

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

 

这道题最典型的方法就是用移位统计,就比如统计9的二进制1个数:

1.9的二进制位1001,9-1的二进制位1000.

2.两者做与运算,结果为1表示最后一位为1,否则为0

3.将1001向右移位一位然后重复上述步骤直到该数字为0停止

 

代码实现如下:

复制代码
 1 #include <iostream> 2 using namespace std; 3  4 int NumberOf1(int n) 5 { 6     int count=0; 7     while(n) 8     { 9         if(n&1)10             count++;11         n=n>>1;12     }13     return count;14 }15 16 17 int main(int argc, char* argv[])18 {19     int number;20     cout<<"Please input the Number: ";21     cin>>number;22     cout<<"count '1': "<<NumberOf1(number)<<endl;23     return 0;24 }
复制代码

运行截图:

 

但是有个问题,这种方法不适合负数

因为负数的右移位后最高位的符号位仍然需要保留。

剑指offer一书提供一种方法:

其思路是这样:

1.首先取一个flag整数,并且让flag=1;

2.让flag&number 如果为1则证明最低位为1

3.flag<<1 同时flag&number 如果为1则证明次低位为1.

4.知道flag移位了sizeof(number)*8次便完成统计。

 

说明:flag的数据类型应与number的数据类型一致。

 

这种方法实现如下:

复制代码
 1 int NumberOf1(int n) 2 { 3  4     int count=0; 5     unsigned int flag=1; 6     while(flag) 7     { 8         if(n&flag) 9             count++;10 11         flag=flag<<1;12     }13     return count;14 }
复制代码

运行结果:

 

 

其实我们可以分析一下负数在内存中存储方式:

以-9为例,将设int战4个字节

原码:1000 0000|0000 0000|0000 1001

补码(原码除符号位之外取反加1):1111 1111|1111 1111|1111 0111

 

我们既然是这样我们可以对负数来说:

1.先取负数的相反数-number,此时-number>0

2.-number-1,同时让-number-1按照方法1的方式右移位计算count

3.取sizeof(num)*8-count即为负数在内存中存储的1的个数

 

 

验证代码如下:

复制代码
 1 #include <iostream> 2 using namespace std; 3  4 int NumberOf1(int n) 5 { 6  7     int count=0; 8     n=n-1; 9     while(n)10     {11         if(n&1)12             count++;13         n=n>>1;14     }15 16     count=sizeof(n)*8-count;17     18     return count;19 }20 21 22 int main(int argc, char* argv[])23 {24     int number;25     cout<<"Please input the Number: ";26     cin>>number;27     cout<<"count '1': "<<NumberOf1(-number)<<endl;28     return 0;29 }
复制代码

验证结果:


0 0
原创粉丝点击