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

题目:输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。

微机原理基础:

①原码表示法规定:用符号位和数值表示带符号数,正数的符号位用“0”表示,负数的符号位用“1”表示,数值部分用二进制形式表示。 
②反码表示法规定:正数的反码与原码相同,负数的反码为对该数的原码除符号位外各位取反。 
③补码表示法规定:正数的补码与原码相同,负数的补码为对该数的原码除符号位外各位取反,然后在最后一位加1. 
④正零和负零的补码相同,[+0]补=[-0]补=0000 0000

例如: -5

(一共32位)

原码:1000 0000 0000 0000 0000 0000 0000 0101 

反码:1111  1111  1111  1111  1111 1111  1111  1010 (符号位不变,将原码逐位取反)

补码:1111  1111  1111  1111  1111 1111  1111  1011 (符号位不变,+1)

对于正数三码一致;我们这里介绍下如何手动计算一个正数的二进制表示。

比如:7的二进制 0111,计算过程如下,不断处以2,直到商为0。

另:

本题输入的是int类型,int类型取值范围:int型为有符号32位整数,占4个字节,取值范围在-2,147,483,648~2,147,483,647之间。

更多参考:https://blog.csdn.net/q304929130/article/details/48104451

思路:对于整数,我们直接转成二进制,然后统计1的个数;

           对于0,直接返回0

           对于负数,我们首先得到其绝对值,然后逐位取反(得到反码);最后末位+1(得到补码);我们直接统计0的个数,然后用32去减掉

【注意:上述有个取绝对值操作,当 输入为: -2,147,483,648的时候,取绝对值是会溢出的,所以这种情况单独处理,具体见代码】

  1 #include<iostream>
  2 #include<vector>
  3 using namespace std;
  4 
  5 // 输入:n:一个int类型的正整数
  6 // 输出:binary:n的二进制表示形式
  7 // 功能:获取一个正整数的二进制
  8 void getBinary(int n, vector<int>& binary)
  9 {
 10      // 初始化
 11     int remainder = n % 2;//余数
 12     int quotient = n / 2;//
 13     binary.push_back(remainder);
 14     while (quotient != 0) //商 = 0则停止计算
 15     {
 16         remainder = quotient % 2;//余数
 17         quotient = quotient / 2;//
 18         binary.push_back(remainder);
 19     }
 20 }
 21 
 22 int  NumberOf1(int n)
 23 {
 24     vector<int> binary;
 25     int count = 0; // 1的个数
 26     // <1> 正数
 27     if ( n > 0)
 28     {
 29         getBinary(n, binary);
 30         for (vector<int>::iterator itr = binary.begin(); itr != binary.end(); itr ++)
 31         {
 32             if (*itr == 1)
 33             {
 34                 count++;
 35             }
 36         }
 37         return count;
 38     }
 39     // <2> 0
 40     else if (n == 0)
 41     {
 42         return count;
 43     }
 44     // <3> 特殊情况
 45     // https://blog.csdn.net/q304929130/article/details/48104451
 46     else if (n == (-2147483648))// int型为有符号32位整数,占4个字节,取值范围在-2,147,483,648~2,147,483,647之间。
 47     {
 48         return 1;
 49     }
 50     // <4> 负数
 51     else
 52     {
 53         int nabs = abs(n);// nabs最大取 ‭01111111111111111111111111111111‬   (2147483647)
 54         //n change to Bianry
 55         vector<int> binary;
 56         getBinary(nabs, binary);
 57         //【计算原码】逐位取反
 58         for (vector<int>::iterator itr = binary.begin(); itr != binary.end(); itr++)
 59         {
 60             if (*itr == 1) 
 61                 *itr = 0;
 62             else
 63                 *itr = 1;
 64         }
 65         // 【计算补码】最后位加1
 66         for (int i = 0; i < binary.size(); i++)
 67         {
 68             //这里有点小技巧
 69             if (binary[i] == 0)
 70             {
 71                 binary[i] = 1;
 72                 break;
 73             }
 74             else
 75             {
 76                 binary[i] = 0;
 77             }
 78         }
 79         // 统计0的个数
 80         for (vector<int>::iterator itr = binary.begin(); itr != binary.end(); itr++)
 81         {
 82             if (*itr == 0)
 83             {
 84                 count++;
 85             }
 86         }
 87         return (32 - count);
 88     }
 89 }
 90 
 91 
 92 int main()
 93 {
 94     cout << "0 = " << NumberOf1(0) << endl;
 95     cout << "3 = " << NumberOf1(3) << endl;
 96     cout << "11 = " << NumberOf1(11) << endl;
 97     cout << "5 = " << NumberOf1(5) << endl;
 98     cout << "7 = " << NumberOf1(7) << endl;
 99     cout << "12 = " << NumberOf1(12) << endl;
100     cout << "255 = " << NumberOf1(255) << endl;
101     cout << "-5 = " << NumberOf1(-5) << endl;
102     cout << "-1 = " << NumberOf1(-1) << endl;// 2 应该是32
103     cout << "-127 = " << NumberOf1(-127) << endl; // -2147483648
104     cout << "-2147483648 = " << NumberOf1(-2147483648) << endl; // 1
105     return 1;
106 }

例如:我们通过计算器来验证, 猜测:由于我们是64位系统,这里显示出来是64位;在本题,我们默认是32位系统。

我们看到有一个0;所以 32 - 1 = 31(符合上述代码计算结果。)

同理:32 - 6 = 26;

同理:32 - 31 = 1;

原文地址:https://www.cnblogs.com/winslam/p/9476972.html