剑指offer11_二进制中1的个数_题解

二进制中1的个数

题目描述

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

示例1

输入

10

返回值

2

分析

方案一:二进制移位法

将整数看成二进制,让掩码mask从右往左与n的每一位进行&操作,若与操作结果为1,则n的当前位为1,bits加1,否则当前位为0,继续左移mask。

/**
时间复杂度:O(32)
空间复杂度:O(1)
**/
class Solution
{
public:
    int NumberOf1(int n){
        int bits = 0;
        int mask = 1;
        for(int i = 0; i < 32; i++){
            if((n & mask) != 0){
                bits++;
            }
            mask <<= 1;
        }
        return bits;
    }
};

思考

  • 为什么不采用从左往右移位?
    • 如果n本身为负数(负数在计算机中用补码表示)向右移位最高位补1。程序会产生死循环
class Solution
{
    int NumberOf1(int n)
    {
        int bits = 0;
        while (n != 0)
        {
            if ((n & 1) != 0)
            {
                bits++;
            }
            n >>= 1;
            cout << n << endl;
        }
        return bits;
    }
};

栗子:假设 \(n=-1\) ,则\(n\) 的原码和补码表示分别为

\[1000,0001\tag{原码} \]

\[1111,1111\tag{补码} \]

-1的补码右移结果还是\(1111,1111\),也就是说-1右移的结果还是-1

故n无法减为0,产生死循环

方案二:巧用 \(n\&(n-1)\)

\(n\&(n-1)\) 解析: 二进制数字 \(n\) 最右边的 \(1\) 变成 \(0\) ,其余不变。

Picture10.png

/**
时间复杂度:O(n)
设 M 为二进制数字 n 中 1 的个数,则需循环 M 次(每轮消去一个 1 ),占用 O(M)。
空间复杂度:O(1)
**/
class Solution
{
public:
    int NumberOf1(int n){
        int sum = 0;
        while (n != 0){
            sum++;
            n &= (n - 1);
        }
        return sum;
    }
};

方案三:bitset

C++的 bitset 在 STL 的 bitset 头文件中,它是一种类似数组的结构,它的每一个元素只能是0或1,每个元素仅占用1bit 空间。

class Solution
{
public:
    int NumberOf1(int n){
        bitset<32> bs(n);
        return bs.count();// 返回1的个数
    }
};
posted @ 2020-12-09 18:45  RiverCold  阅读(99)  评论(0编辑  收藏  举报