1、问题描述
输入一个负整数num,对于 0 ≤ i ≤ n u m 0\le i \le num 0≤i≤num中的每个数 i i i,计算其二进制表示中1的个数,并将它们作为数组返回。
2、解题思路
- 思路1:参考《剑指offer》-[第2章:面试需要的基础知识 - 2.4:算法与数据操作- 2.4.3:位运算] 题10:二进制中1出现的次数,对于每个整数,要想知道其二进制表示中1的个数,可以不断地对该数进行减1然后与自身与操作,知道该数变成0为止。减1实际上是将该数二进制表示中右边地第一个1变成0,然后与自身与完之后,右边第一个1及其后面所有的数都会变成0。由于这个整数有多少个1,就要进行多少次这样额操作,所以时间复杂度为 O ( n ∗ s i z e o f ( I n t e g e r ) ) O(n*sizeof(Integer)) O(n∗sizeof(Integer))
- 思路2:也可以采用动态规划解决。对于0-num的所有数字,无非分为两类,奇数和偶数。
- 由于奇数的二进制表示中的最后一位一定是1,偶数的二进制表示最后一位一定是0。所以,如果将它们分别除以2,那么
- 对于每一个奇数来说,它的二进制表示中1的个数一定比它除以2的那个数的二进制表示中1的个数多1,因为除以2是右移1位,相当于把该数末尾的那个1去掉了;比如1=0001,3=0011;2=0010,5=0101。
- 对于每一个偶数来说,它的二进制表示中1的个数一定和它除以2的那个数的二进制表示中1的个数相等,因为除以2是右移,相当于把该偶数末尾的0去掉了。例如:1=0001,2=0010;4=0100,8=1000.
- 所以,动态规划的状态转移方程是:
-
B
i
t
(
n
)
=
{
B
i
t
(
n
/
2
)
+
1
i
f
n
为
奇
数
B
i
t
(
n
/
2
)
i
f
n
为
偶
数
Bit(n)=\begin{cases}Bit(n/2) + 1 & if \ n为奇数\\ Bit(n/2) & if \ n为偶数 \end{cases}
Bit(n)={Bit(n/2)+1Bit(n/2)if n为奇数if n为偶数
这种方法的时间复杂度为 O ( n ) O(n) O(n)。
3、代码实现
class Solution:
def countBits(self, num: int) -> List[int]:
result = [0] * (num + 1)
for i in range(0, num + 1):
if i & 1 == 0:
result[i] = result[i>>1]
else:
result[i] = result[i>>1] + 1