Leetcode刷题之路——338. 比特位计数
本文最后更新于:2021年3月3日 下午
题目描述
给定一个非负整数 num 。对于 0 ≤ i ≤ num 范围中的每个数字 i ,计算其二进制数中的 1 的数目并将它们作为数组返回。
示例 1:
输入: 2
输出: [0,1,1]示例 2:
输入: 5
输出: [0,1,1,2,1,2]进阶:
- 给出时间复杂度为
O(n*sizeof(integer))的解答非常容易。但你可以在线性时间O(n)内用一趟扫描做到吗? - 要求算法的空间复杂度为
O(n)。 - 你能进一步完善解法吗?要求在C++或任何其他语言中不使用任何内置函数(如 C++ 中的
__builtin_popcount)来执行此操作。
题目分析
个人初尝试
比较直接的思路,把每一个数都计算一遍,然后存下来输出。每一个数用辗转相除法算出1的个数。
具体代码如下:
class Solution {
public:
int countone(int num) {
int count = 0;
while(num >= 2) {
if(num%2 == 1) {
++count;
}
num = num/2;
}
if(num == 1) {
++count;
}
return count;
}
vector<int> countBits(int num) {
vector<int> result(num + 1);
for(int i=0; i<=num; ++i) {
result[i] = countone(i);
}
return result;
}
};在第一次时出现了问题,得到的答案不对。仔细逐行分析之后发现是 while 中的 if 放到了除法后面,这就导致了取余的时候实际已经不是最开始的那个数了。调整顺序后问题解决。
虽然达成了题目的要求,但是对于进阶的要求其实并不满足,时间上仍然比较长。由于自己没有啥更好的思路了,看题解!
动态规划
最低有效位
对于任意一个正整数 x ,将其右移一位,相当于将该数的最低位去掉。如果去掉最低位的数的比特数已经知道,则原数的比特数也可以推理得到。如果原数为偶数,则比特数相同;为奇数则比特数 +1 。即
$$
bit[x] =
\begin{cases}
bit[{x \over 2}], & \text{如果 $x$ 是偶数} \
bit[{x \over 2}] + 1, & \text{如果 $x$ 是奇数} \
\end{cases}
$$
按照这个思路,从0开始遍历即可得到所需的bit值。其中奇数偶数的判断可以化简为对2取模。
具体代码如下
class Solution {
public:
vector<int> countBits(int num) {
vector<int> result(num + 1);
for(int i=0; i<=num; ++i) {
result[i] = result[i >> 1] + i%2;
}
return result;
}
};一些细节的总结
- 注意代码运行的逻辑顺序!
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!