难度: Medium
原题连接
内容描述
Given a non negative integer number num. For every numbers i in the range 0 ≤ i ≤ num calculate the number of 1's in their binary representation and return them as an array.
Example 1:
Input: 2
Output: [0,1,1]
Example 2:
Input: 5
Output: [0,1,1,2,1,2]
Follow up:
It is very easy to come up with a solution with run time O(n*sizeof(integer)). But can you do it in linear time O(n) /possibly in a single pass?
Space complexity should be O(n).
Can you do it like a boss? Do it without using any builtin function like __builtin_popcount in c++ or in any other language.
思路 1 - 时间复杂度: O(Nk) k is number of bits in num*- 空间复杂度: O(N)******
O(n*sizeof(integer)) 算法,其实就是把count of 1 bit拿来用:
class Solution(object):
def countBits(self, num):
"""
:type num: int
:rtype: List[int]
"""
def hammingWeight(n):
cnt = 0
while n != 0:
n &= n -1
cnt += 1
return cnt
res = []
for i in range(num+1):
res.append(hammingWeight(i))
return res
Space complexity should be O(n).
Can you do it like a boss? Do it without using any builtin function like __builtin_popcount in c++ or in any other language.
思路 1 - 时间复杂度: O(N)- 空间复杂度: O(N)******
DP 算法
DP 的思路其实不难,就是“把每天当成是末日来相待”,并且这一天发生的事能记下来就记下来。 转换到实际问题上,就是把每一步都当时是最后一步来操作,然后沿途记下一些以后需要的数据即可。
本题是求二进制数中1
的个数,首先,创建一个数组dp
,数组的索引i
就是数字i
,索引i
对应的值就是数字i
二进制数的1
的个数。
我们知道,任何一个十进制数字num
都可以转换成二进制,并且,转换后的二进制长度是x = floor(log(num, 2)) + 1
位,这x
位数字除了第一位是1
之外,其他位都是0
或1
。
所以,可以把num
拆成两个数的和,其中第一个数是p = 2**(x-1)
,第二个数就是num - p
。如果num == p
, 因为p = 2**(x-1)
中数字1
的个数是1
,那么此时num
的二进制数中的1
的个数就是1
,即dp[num] = 1
,否则,dp[num] = dp[p] + dp[num-p]
(num-p
一定小于p
)。
总结一下,关键点在于c = a + b
,如何找到合适的a
、b
.
首先只有一轮循环,在每一轮循环里面有log函数,但是基本上可以忽略不计,所以总时间复杂度为O(N),空间也为O(N)
class Solution(object):
def countBits(self, num):
"""
:type num: int
:rtype: List[int]
"""
from math import floor, log
dp = [0] * (num+1)
for i in range(1, num+1):
x = floor(log(i, 2)) + 1
p = int(pow(2, x-1))
if p == i:
dp[i] = 1
else:
dp[i] = dp[p] + dp[i-p]
return dp
思路 2 - 时间复杂度: O(N)- 空间复杂度: O(N)******
dp的另外一种方法,状态方程为 P(x) = P(x&(x-1)) + 1
beats 95.17%
class Solution(object):
def countBits(self, num):
"""
:type num: int
:rtype: List[int]
"""
dp = [0] * (num+1)
for i in range(1, num+1):
dp[i] = dp[i&(i-1)] + 1
return dp