剑指offer14_二进制中1的个数
二进制中1的个数
输入一个 32位整数,输出该数二进制表示中 1 的个数。
注意:
- 负数在计算机中用其绝对值的补码来表示。
数据范围
−100≤ 输入整数 ≤100
样例1
输入:9
输出:2
解释:9的二进制表示是1001,一共有2个1。
样例2
输入:-2
输出:31
解释:-2在计算机里会被表示成11111111111111111111111111111110,一共有31个1。
算法描述
通过迭代计算整数 n
的二进制表示中 1 的个数,步骤如下:
- 转换为无符号整数:避免负数右移时的符号扩展问题
- 循环直到
n = 0
:- 检查最低位是否为
1
:n & 1 == 1
则计数器+1
- 右移一位:
n = n >> 1
(无符号右移自动补0)
- 检查最低位是否为
- 返回计数器值
时间复杂度
O ( log n ) O(\log n) O(logn)
每次迭代将 n n n 减半(右移一位),最多执行 log 2 n \log_2 n log2n 次
关键点:负数处理
unsigned int u = static_cast<unsigned int>(n); // 关键转换
- C++ 中右移负数时最高位补
1
,会导致死循环 - 转换为无符号整数后,右移时最高位补
0
C++ 实现
int countOnes(int n) {unsigned int u = static_cast<unsigned int>(n); // 处理负数的核心步骤int count = 0;while (u != 0) {if (u & 1) count++; // 检查最低位u >>= 1; // 无符号右移(自动补0)}return count;
}
示例说明
输入 | 二进制 | 步骤分解 | 输出 |
---|---|---|---|
5 | 00000101 | 2个1 | 2 |
-3 | 11111101 → 转无符号:253 (11111101 ) | 7个1 | 7 |
注意:负数的二进制补码表示在转换为无符号整数时,其原始位模式保持不变,但右移行为变为逻辑移位(补0)而非算术移位(补符号位)。