一. 题目描述
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:
For num = 5
you should return [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.
Hint:
You should make use of what you have produced already.
Divide the numbers in ranges like [2-3], [4-7], [8-15] and so on. And try to generate new range from previous.
Or does the odd/even status of the number help you in calculating the number of 1s?
二. 题目分析
题目大意是,给定一个非负整数num
,对于每一个满足0 ≤ i ≤ num
的数字i
,计算这些数字的二进制表示中1
的个数,并以数组vector的形式返回。
题目还给出了一系列提示:
很容易想到运行时间为:O(n*sizeof(integer))
的解法。但你可以用线性时间:O(n)
的一趟算法完成吗?空间复杂度应当为:O(n)
。
你可以像老板那样?不要使用任何内建函数(比如C++的__builtin_popcount
)。
提示:
你应该利用已经得到的结果。
将数字拆分为诸如 [2-3], [4-7], [8-15]
之类的范围。并且尝试根据已经生成的范围产生新的范围。
也许数字的奇偶性可以帮助你计算1
的个数?
从题目中给出的诸多提示,加上手写实例,容易发现一些规律,并得到多种方法,这里只列出两种位运算的解决方法。
方法一:
0 0000
1 0001
2 0010 // 左移一位,发现位数和(2/2 = 1)一致
3 0011 // 左移一位,发现位数和(2/2 = 1)一致,只是3为奇数,需要比1多1个1
4 0100
5 0101
6 0110
7 0111
8 1000 // 左移一位,发现位数和(8/2 = 4)一致
9 1001 // 左移一位,发现位数和(9/2 = 4)一致,只是9为奇数,需要比4多1个1
10 1010
11 1011
12 1100
13 1101
14 1110 // 左移一位,发现位数和(14/2 = 7)一致
15 1111 // 左移一位,发现位数和(15/2 = 7)一致,只是15为奇数,需要比7多1个1
根据以上实例,设F[n]
表示正整数n
的二进制个数,则可得到以下方程:
F[n] = F[n / 2] + F[n] & 1
,根据这个方程,只需遍历一次0 ~ num
的整数,即可得到各整数的二进制表示中含1
的个数。
方法二:
0 0000
1 0001
2 0010
3 0011 // 对于非2的幂次数n,其二进制表示中1的个数比(n & (n - 1))多一个
4 0100
5 0101
6 0110
7 0111
8 1000 // 对于2的幂次数n,(n & (n - 1)) = 0,同样满足二进制表示中1的个数比(n & (n - 1))多一个
9 1001
10 1010
11 1011
12 1100
13 1101
14 1110
15 1111
该规律较难找出,可得到以下方程:F[n] = F[n & (n - 1)] + 1
三. 示例代码
// C++,方法一
class Solution {
public:
vector<int> countBits(int num) {
vector<int> result;
if (num < 0) return result;
result.push_back(0);
for (int i = 1; i <= num; ++i)
{
result.push_back(result[i >> 1] + (i & 1));
}
return result;
}
};
# Python,方法一
class Solution(object):
def countBits(self, num):
""" :type num: int :rtpye: List[int] """
result = [0]
for i in range(1, num + 1):
result += result[i >> 1] + (i & 1),
return result
// C++,方法二
class Solution {
public:
vector<int> countBits(int num) {
vector<int> result;
if (num < 0) return result;
result.push_back(0);
for (int i = 1; i <= num; ++i)
{
result.push_back(result[i & (i - 1)] + 1);
}
return result;
}
};
# Python,方法二
class Solution(object):
def countBits(self, num):
""" :type num: int :rtype: List[int] """
result = [0]
for i in range(1, num + 1):
result += result[i & (i - 1)] + 1,
return result
四. 小结
最近项目组中期检查,耗费了不少时间,算法也没之前写的多了,思想容易迟钝。