面试题14:二进制中1 的个数

1 题目

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

2 思路

1.由于负数右移会在最左边补1,因此不能右移,否则可能陷入死循环
2.首先判断n和1做与运算判断n的最低位是不是为1.接着把1左移一位得2,再和n做与运算,就能判断n的磁低位是不是1……,反复左移,每次都能判断n的其中一位是不是1.
3.如果一个整数与1做与运算结果是1,表示该整数最右边一位是1,否则是0.

3 代码

int  NumberOf1(int n)
{
         int cnt = 0;
         unsigned int flag = 1;
         while(flag){
            if(n & flag)cnt++; //不管n是不是负数,都成立
             cout<<flag<< " after ";
             flag=flag<<1;
             cout<<flag<<endl;
         }
         return cnt;
}

4 优化

上述解法,循环次数等于整数的二进制位数,32位需要循环32次。
我们可以把一个整数减去1,

  1. 一个不为0的整数,那么它的二进制表示中至少有一个1,
  2. 我们可以假设最后一位不是1而是0的情况,若最右边的1位于第m位,减去1之后,该位变成0,它之后的每一位都取反为1,
  3. 若最后一位为1,则直接取反。
    4.把一个整数减去1后再和原整数做与运算,会把该整数最右边的1变成0,因此1的个数会减少一位,每与一次减少一个1,直到输入的数为0.
int  NumberOf2(int n)
{
         int cnt = 0;
         unsigned int flag = 1;
         while(n){
             cnt++;
             n=n&(n-1);
         }
         return cnt;
}

5 拓展

输入两个整数m和n,计算需要改变m的二进制表示中的多少位才能得到n?
比如 10 的二进制为1010,13的二进制为1101,需要改变3位才能得到1101.可以分为两步:1,求解这两个数的异或,第二步统计异或结果中1的位数。

posted @ 2021-03-29 08:59  一地斜阳  阅读(87)  评论(0)    收藏  举报