hammingWeight的动态规划
以前做过一道题(191. Number of 1 Bits )讲的是给定一个数,求它二进制下的1的个数。如果是对于一个数,那么可以用位运算黑魔法:(对末尾做与1的与运算)
class Solution(object):
def hammingWeight(self, n):
ans=0
while n:
if n&1==1:
ans+=1
n=n>>1
return ans
今天碰到了一个进阶版的题目,(338. Counting Bits )题目要求是在 O(n) 的时间和空间里计算出 [0,n] 区间里所有整数的二进制下的1的个数(Hamming weight - Wikipedia)。
O(n) 的时间要求是有点小苛刻的,首先遍历一次 [0,n] 区间里所有整数就需要 O(n) ,那么每次小操作需要在 O(1) 内才是可以的,首先想到的是能不能用上面leetcode191的做法来套用呢?不妨分析一下复杂度。
容易看出对于一个数
n
,这样的操作(主要是移位操作)时间复杂度是
很遗憾的是并不能直接满足题目中所要求的 O(n) 复杂度,如果消耗一点空间换时间,利用上述的方法还是有机会降到 O(n) 的动态规划的思路:
用
res
表示最终的结果,改写上述方法为一个一维的递推式:
也就是说一直维护这样的一个一维数组,每次都记录其结果,显然时间复杂度是 O(n) ,空间也是 O(n) ,满足题目要求。不过这并不是我首先想到的思路,我首先想到的是,直接从n的p进制下的数码之和角度入手。
class Solution(object):
def countBits(self, num):
ans=[0]
for x in range(1,num+1):
ans+=[ans[x>>1]+(x&1)]
return ans
n的p进制下的数码之和
用
Sp(n)
表示n的p进制下的数码之和,用
ap
表示
n!
的标准分解中
p
的幂次,即
容易得出每一项系数的准确公式:
接着进行一下数学推导:
这个推导需要用到勒让德公式,即 n! 中 p 的幂次为