【LeetCode-338】比特位计数
问题
给定一个非负整数 num。对于 0 ≤ i ≤ num 范围中的每个数字 i ,计算其二进制数中的 1 的数目并将它们作为数组返回。
示例
输入: 5
输出: [0,1,1,2,1,2]
解答1:暴力方法
class Solution {
public:
vector<int> countBits(int num) {
vector<int> res(num + 1);
for (int i = 1; i <= num; i++)
res[i] = counter(i);
return res;
}
private:
int counter(int n) {
int ans = 0;
while (n) {
n &= n - 1;
ans++;
}
return ans;
}
};
重点思路
这里使用了n = n & (n - 1)
这个统计二进制1个数的技巧。
解答2:带记忆递归
class Solution {
public:
vector<int> countBits(int num) {
res.push_back(0);
for (int i = 1; i <= num; i++)
res.push_back(counter(i));
return res;
}
private:
vector<int> res;
int counter(int n) {
if (n < res.size()) return res[n];
return counter(n >> 1) + (n & 1);
}
};
重点思路
由于res中存储了数字n
前的所有结果,所以可以作为递归的memo
使用。递归的返回结果为counter(n >> 1) + (n & 1)
,当输入为偶数时,右移;输入为奇数时,最低位为1,则右移后结果需要加上1。
解答3:动态规划
class Solution {
public:
vector<int> countBits(int num) {
vector<int> res(num + 1);
for (int i = 1; i <= num; i++)
res[i] = res[i >> 1] + (i & 1);
return res;
}
};
重点思路
带记忆的递归能很容易地转化为动态规划,很容易从递归的递推方程转化到动态规划的状态转移方程。