持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第17天,点击查看活动详情
一、题目描述:
给你一个整数 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
提示:
- 0 <= n <= 10^5
进阶:
很容易就能实现时间复杂度为 的解决方案,你可以在线性时间复杂度 O(n) 内用一趟扫描解决此问题吗? 你能不使用任何内置函数解决此问题吗?(如,C++ 中的 __builtin_popcount )
二、思路分析:
起初思路为:将0,1,2,3数组初始化,为0,1,1,2。用动态规划进行数组叠加更新。
因为大于1的数每个数的第一个二进制数都为1,所以我们默认每个大于1的数必有1个
所以我们更新4,4和0的数组元素对应,为1+dp[0],5和1的元组数对应为1+dp[1]
6和2的数组对应为1+dp[2],所以我们想到dp叠加数组为dp[i%4],能够更新之前的数组,且数组正确,在运行一次知道
我又得到了一个新的问题,当dp[12]时我们得到dp[12]=1+dp[0]不对,因为12的二进制为1100我们是将第一位去掉得到了100,而100等与4所以我们必须让dp[12]=1+dp[4]而4可以由12%8得到,所以我得到当i=8时我们的%4会更新,而且更新到2^3=8,所以我们只需要判断当前i是否为2的幂,如果为2的幂则可以进行更新k=i。将k的初值设为0
出现了新的错误,如果n<3会出错,所以我们进行验证将初始化去掉,只保留dp[0]的初始化,结果为dp[1]=1+dp[0]=1,dp[2]=1+dp[0]=1
dp[3]=1+dp[1]=2。
至此解决问题。
三、AC 代码:
class Solution:
def countBits(self, n: int) -> List[int]:
dp=[0]*(n+1)
k=0
for i in range(1,n+1):
if i&(i-1) == 0 :
k=i
dp[i]=1+dp[i%k]
return dp