题解:AcWing 801 二进制中1的个数

【题目来源】

AcWing:801 二进制中1的个数 - AcWing题库

【题目描述】

给定一个长度为 \(n\) 的数列,请你求出数列中每个数的二进制表示中 \(1\) 的个数。

【输入】

第一行包含整数 \(n\)

第二行包含 \(n\) 个整数,表示整个数列。

【输出】

共一行,包含 \(n\) 个整数,其中的第 \(i\) 个数表示数列中的第 \(i\) 个数的二进制表示中 \(1\) 的个数。

【输入样例】

5
1 2 3 4 5

【输出样例】

1 1 2 1 2

【核心思想】

  1. 问题分析:给定 \(n\) 个整数,求每个整数的二进制表示中 \(1\) 的个数。这是一个位运算问题,关键在于高效地统计二进制中 \(1\) 的数量。

  2. 算法选择

    • lowbit 技巧:利用 x & -x 获取 \(x\) 的二进制表示中最低位的 \(1\) 所对应的值
    • 迭代消去:不断减去最低位的 \(1\),直到 \(x\) 变为 \(0\),统计减法次数即为 \(1\) 的个数
  3. 关键步骤

    • 定义 lowbit 函数lowbit(x) = x & -x
      • 原理:-x\(x\) 的补码(按位取反后加 \(1\)),x & -x 可以提取出最低位的 \(1\)
      • 例如:x = 10100(二进制),-x = 01100(补码),x & -x = 00100 = 4
    • 统计每个数字(对于每个输入的 \(x\)):
      • 初始化 res = 0
      • 循环(当 \(x \neq 0\)):
        • x -= lowbit(x):减去最低位的 \(1\)
        • res++:计数器加 \(1\)
      • 输出 res
  4. 时间/空间复杂度

    • 时间复杂度:\(O(n \cdot \log x)\),对于每个数字,最多进行 \(\log x\) 次循环(\(x\) 的二进制位数)
    • 空间复杂度:\(O(1)\),仅使用常数额外空间
  5. lowbit 的核心思想

    • 补码性质-x = ~x + 1,即 \(x\) 的按位取反加 \(1\)
    • 提取最低位 1x & -x 的结果只保留 \(x\) 中最低位的 \(1\),其余位都为 \(0\)
    • 快速消去:每次减去 lowbit(x) 可以消去一个 \(1\),比逐位检查更高效
    • 适用场景
      • 统计二进制中 \(1\) 的个数
      • 树状数组(Binary Indexed Tree)中的索引计算
      • 快速获取最低位的 \(1\) 的位置

【解题思路】

【算法标签】

位运算

【代码详解】

#include <bits/stdc++.h>
using namespace std;
int lowbit(int x)  // 返回x的二进制表示中最低位的1所对应的值
{
    return x & -x;
}
int main()
{
    int n;
    cin >> n;  // 输入数字个数
    while (n--)  // 处理每个数字
    {
        int x;
        cin >> x;
        int res = 0;  // 统计1的个数
        while (x)  // 当x不为0
        {
            x -= lowbit(x);  // 减去最低位的1
            res++;  // 计数器+1
        }
        cout << res << " ";  // 输出结果
    }
    return 0;
}

【运行结果】

5
1 2 3 4 5
1 1 2 1 2
posted @ 2026-06-14 10:37  团爸讲算法  阅读(5)  评论(0)    收藏  举报