题目描述
给定一个非负整数 n,计算从 0 到 n 的每个数字的二进制表示中 1 的个数,并以数组形式返回。要求:
- 算法时间复杂度为 O(n)O(n)
- 空间复杂度为 O(n)O(n)
解题思路
核心思想:利用动态规划高效计算二进制中1的个数,通过已计算的结果推导新值。
-
动态规划方法:
- 状态定义:
dp[i]表示数字i的二进制中1的数量 - 转移方程:
dp[i] = dp[i >> 1] + (i & 1)- 解释:数字
i的1的数量 =i/2的1的数量 +i的最低位是否为1
- 初始化:
dp = 0
- 状态定义:
-
关键特性:
- 奇偶规律:
- 偶数:
dp[i] = dp[i/2](最低位为0) - 奇数:
dp[i] = dp[i/2] + 1(最低位为1)
- 偶数:
- 位运算优化:使用
i >> 1代替除法,i & 1代替取模
- 奇偶规律:
复杂度分析
| 指标 | 值 | 说明 |
|---|---|---|
| 时间复杂度 | O(n)O(n) | 只需遍历一次数组 |
| 空间复杂度 | O(n)O(n) | 存储结果数组 |
代码实现
- JavaScript
var countBits = function(n) {
const dp = new Array(n + 1).fill(0);
for (let i = 1; i <= n; i++) {
dp[i] = dp[i >> 1] + (i & 1);
}
return dp;
};
- python
def countBits(n: int) -> list[int]:
dp = [0] * (n + 1)
for i in range(1, n + 1):
dp[i] = dp[i >> 1] + (i & 1)
return dp
- rust
impl Solution {
pub fn count_bits(n: i32) -> Vec {
let n = n as usize;
let mut dp = vec![0; n + 1];
for i in 1..=n {
dp[i] = dp[i >> 1] + (i & 1) as i32;
}
dp
}
}
实际应用场景
- 加密算法:快速计算汉明权重(如SHA-256)
- 图像处理:二进制图像的特征提取
- 数据压缩:评估二进制数据的熵值
- 遗传算法:计算DNA序列的相似度
- 错误检测:CRC校验中的位计算
相似题目
- 汉明距离
- 解题思路:
x ^ y后计算二进制中1的数量 - 关联点:相同位计数技术
- 解题思路:
- 数字的补数
- 解题思路:取反位并清除前导零
- 关联点:位操作基础
- 二进制表示中质数个1
- 解题思路:组合位计数与质数判断
- 进阶应用:位计数结果的二次处理