跳到主要内容

338. 比特位计数

题目描述

给你一个整数 n,对于 0 <= i <= n 中的每个 i,计算其二进制表示中 1 的个数 ,返回一个长度为 n + 1 的数组 ans 作为答案。

示例

示例 1:

输入:n = 2
输出:[0,1,1]
解释:
0 --> 0
1 --> 1
2 --> 10

示例 2:

输入:n = 5
输出:[0,1,1,2,1,2]
解释:
0 --> 0
1 --> 1
2 --> 10
3 --> 11
4 --> 100
5 --> 101

解题思路

第一步:理解问题本质

需要计算 0n 每个数的二进制中 1 的个数。关键问题是:如何利用已计算的结果来推导新的结果?

第二步:暴力解法

对每个数,逐位检查是否为 1

class Solution:
def countBits(self, n: int) -> List[int]:
ans = []
for i in range(n + 1):
count = 0
x = i
while x:
count += x & 1
x >>= 1
ans.append(count)
return ans

为什么不够好:时间复杂度 O(n log n)。

第三步:动态规划(最高有效位)

核心洞察

  • 任何正整数 i 都可以表示为 highBit + (i - highBit),其中 highBit 是小于等于 i 的最大 2 的幂
  • bits[i] = bits[i - highBit] + 1

为什么highBit 只有最高位是 1,所以 i(i - highBit) 多一个 1

第四步:动态规划(最低有效位)

核心洞察i & (i - 1) 清除 i 的最低位的 1

bits[i] = bits[i & (i - 1)] + 1

完整代码实现

from typing import List


class Solution:
"""
比特位计数 - 动态规划(最高有效位)

bits[i] = bits[i - highBit] + 1
highBit 是小于等于 i 的最大 2 的幂

时间复杂度:O(n)
空间复杂度:O(1)(不计输出空间)
"""

def countBits(self, n: int) -> List[int]:
bits = [0]
highBit = 0
for i in range(1, n + 1):
# i & (i - 1) == 0 判断 i 是否是 2 的幂
if i & (i - 1) == 0:
highBit = i
bits.append(bits[i - highBit] + 1)
return bits


# 方法二:最低有效位
class Solution2:
def countBits(self, n: int) -> List[int]:
bits = [0] * (n + 1)
for i in range(1, n + 1):
bits[i] = bits[i & (i - 1)] + 1
return bits


# 方法三:右移
class Solution3:
def countBits(self, n: int) -> List[int]:
bits = [0] * (n + 1)
for i in range(1, n + 1):
bits[i] = bits[i >> 1] + (i & 1)
return bits

示例推演

n = 5 为例:

i二进制i & (i-1) == 0?highBiti - highBitbits[i - highBit]bits[i]
00-0000
111001
2102001
3112112
41004001
51014112

结果:[0, 1, 1, 2, 1, 2]


复杂度分析

解法时间复杂度空间复杂度说明
暴力O(n log n)O(1)逐位检查
DP(最优)O(n)O(1)利用已计算结果

易错点总结

1. i & (i - 1) == 0 的含义

这是判断 i 是否为 2 的幂的经典位运算技巧。2 的幂只有一位是 1,减 1 后低位全变 1,与操作结果为 0

2. 为什么加 1

bits[i] = bits[i - highBit] + 1,因为 ii - highBit 多了一个最高位的 1


相关题目

加载评论中...