位1的个数

这道题出自LeetCode,题目如下:

编写一个函数,输入是一个无符号整数(以二进制串的形式),返回其二进制表达式中数字位数为 '1' 的个数(也被称为汉明重量)。

示例1 :

输入:00000000000000000000000000001011
输出:3
解释:输入的二进制串 00000000000000000000000000001011 中,共有三位为 '1'。

示例2 :

输入:00000000000000000000000010000000
输出:1
解释:输入的二进制串 00000000000000000000000010000000 中,共有一位为 '1'。

示例3 :

输入:11111111111111111111111111111101
输出:31
解释:输入的二进制串 11111111111111111111111111111101 中,共有 31 位为 '1'。

这道题的意思很简单,而且有一种在O(1)时间内计算出结果的巧妙解法。要想统计位1的位数,我们可以利用分而治之的思想进行考虑,就是先去统计前16位中1的位数和后16位中1的位数,然后求和即可。类似地,就要先去统计每8位中1的位数,最后划分到最小单位,就是去统计每1位中1的位数然后求和。统计每1位的1的位数很简单,只要看它是否为1即可,为1数量就是1,否则就是0。至于求和,我们注意到,两个1位数之和最多只会是2,而2的二进制表示是10,用两位足够表达,所以直接相加即可。相加之后的结果,就是每2位中保存了这2位中1的数量。以此类推,可以得到每4位中1的数量,每8位中1的数量,一直到最后32位中1的数量,也就是最终答案。通过的代码如下所示:

class Solution {
public:
    int hammingWeight(uint32_t n) {
        const uint32_t M1 = 0x55555555;  // 01010101010101010101010101010101
        const uint32_t M2 = 0x33333333;  // 00110011001100110011001100110011
        const uint32_t M4 = 0x0f0f0f0f;  // 00001111000011110000111100001111
        const uint32_t M8 = 0x00ff00ff;  // 00000000111111110000000011111111
        const uint32_t M16 = 0x0000ffff; // 00000000000000001111111111111111

        n = ((n >> 1) & M1) + (n & M1);
        n = ((n >> 2) & M2) + (n & M2);
        n = ((n >> 4) & M4) + (n & M4);
        n = ((n >> 8) & M8) + (n & M8);
        n = ((n >> 16) & M16) + (n & M16);

        return n;
    }
};
posted @ 2021-07-24 17:03  异次元的归来  阅读(213)  评论(0编辑  收藏  举报