🚩传送门:牛客题目
力扣题目

题目

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

示例 1:

输入:n = 11 (控制台输入 00000000000000000000000000001011) 输出:3 解释:输入的二进制串 00000000000000000000000000001011 中,共有三位为 ‘1’。

示例 2:

输入:n = 128 (控制台输入 00000000000000000000000010000000) 输出:1 解释:输入的二进制串 00000000000000000000000010000000 中,共有一位为 ‘1’。

示例 3:

输入:n = 4294967293 (控制台输入 11111111111111111111111111111101,部分语言中 n = -3) 输出:31 解释:输入的二进制串 11111111111111111111111111111101 中,共有 31 位为 ‘1’。

解题思路:逐位判断

我们可以直接循环检查给定整数 [NC]120. 二进制中1的个数 - 图1 的二进制位的每一位是否为 [NC]120. 二进制中1的个数 - 图2

复杂度分析

时间复杂度:[NC]120. 二进制中1的个数 - 图3,其中 [NC]120. 二进制中1的个数 - 图4[NC]120. 二进制中1的个数 - 图5 型的二进制位数, [NC]120. 二进制中1的个数 - 图6 。我们需要逐位检查二进制共 [NC]120. 二进制中1的个数 - 图7

空间复杂度:[NC]120. 二进制中1的个数 - 图8,我们只需要常数的空间保存若干变量。

🚩官方代码

  1. public int hammingWeight(int n) {
  2. int cnt = 0;
  3. while (n != 0) {
  4. cnt += n & 1;
  5. n >>>= 1; // 无符号位右移
  6. }
  7. return cnt;
  8. }

解题思路:位运算优化

观察运算:[NC]120. 二进制中1的个数 - 图9,其预算结果恰为把 [NC]120. 二进制中1的个数 - 图10 的二进制位中的最低位的 1 变为 0 之后的结果。

如下面的例子:[NC]120. 二进制中1的个数 - 图11 ,运算结果 4 即为把 6 的二进制位中的最低位的 1 变为 0 之后的结果。

这样我们可以利用这个位运算的性质加速我们的检查过程,在实际代码中,我们不断让当前的 [NC]120. 二进制中1的个数 - 图12[NC]120. 二进制中1的个数 - 图13 做与运算,直到 [NC]120. 二进制中1的个数 - 图14 变为 [NC]120. 二进制中1的个数 - 图15 即可。因为每次运算会使得 [NC]120. 二进制中1的个数 - 图16 的最低位的 [NC]120. 二进制中1的个数 - 图17 被翻转,因此运算次数就等于 [NC]120. 二进制中1的个数 - 图18 的二进制位中 [NC]120. 二进制中1的个数 - 图19 的个数。

复杂度分析

时间复杂度:[NC]120. 二进制中1的个数 - 图20,循环次数等于 [NC]120. 二进制中1的个数 - 图21 的二进制位中 [NC]120. 二进制中1的个数 - 图22 的个数,最坏情况下 [NC]120. 二进制中1的个数 - 图23 的二进制位全部为[NC]120. 二进制中1的个数 - 图24

空间复杂度:[NC]120. 二进制中1的个数 - 图25,我们只需要常数的空间保存若干变量。

🚩官方代码

public class Solution {
    public int hammingWeight(int n) {
        int ret = 0;
        while (n != 0) {
            n &= n - 1;
            ret++;
        }
        return ret;
    }
}