地址:
力扣https://leetcode-cn.com/problems/counting-bits/
题目:
给你一个整数 n ,对于 0 <= i <= n 中的每个 i ,计算其二进制表示中 1 的个数 ,返回一个长度为 n + 1 的数组 ans 作为答案。
示例 1:
输入:n = 2 输出:[0,1,1] 解释: 0 --> 0 1 --> 1 2 --> 10 |
示例 2:
输入:n = 5 输出:[0,1,1,2,1,2] 解释: 0 --> 0 1 --> 1 2 --> 10 3 --> 11 4 --> 100 5 --> 101 |
提示:
0 <= n <= 105 |
进阶:
很容易就能实现时间复杂度为 O(n log n) 的解决方案,你可以在线性时间复杂度 O(n) 内用一趟扫描解决此问题吗?
你能不使用任何内置函数解决此问题吗?(如,C++ 中的 __builtin_popcount )
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/counting-bits
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路:
这个就是 力扣https://leetcode-cn.com/problems/counting-bits/ 的简单扩展版本,多了一个求累加和
方法一、n & (n-1) 统计
int countf(int num)
{
int cnt = 0;
while(num)
{
num = num & (num -1);
cnt++;
}
return cnt;
}
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
int* countBits(int n, int* returnSize){
int len = n + 1;
int *ret = (int *)malloc(sizeof(int) * len);
for(int i=0; i<len; i++)
{
ret[i] = countf(i);
}
*returnSize = len;
return ret;
}
我们可以再优化一下,不用每次都计算
我们直到 求当前 n 含 1 的个数,是循环 n = n & (n-1) ,n 会一直变小直到 0
那么 当前 n 就是上一次 n 含 1 的个数 + 1, 所以我们可以这么做
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
int* countBits(int n, int* returnSize){
int len = n + 1;
int *ret = (int *)malloc(sizeof(int) * len);
ret[0] = 0;
for(int i=1; i<len; i++)
{
ret[i] = ret[i & (i-1)] + 1;
}
*returnSize = len;
return ret;
}
方法二、奇偶数
观察二进制数,比如
4 | 0100 |
5 | 0101 |
6 | 0110 |
7 | 0111 |
奇数含 1 的个数比其小的那个偶数含 1 的个数多 1
偶数情况:
8 | 1000 |
4 | 0100 |
2 | 0010 |
12 | 1100 |
6 | 0110 |
大的偶数都是其小的偶数通过 << 来的,其含 1 个数不变
那么在求大的偶数时,就可以通过已经求得的小的偶数情况直接来
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
int* countBits(int n, int* returnSize){
int len = n + 1;
int *ret = (int *)malloc(sizeof(int) * len);
ret[0] = 0;
for(int i=1; i<len; i++)
{
ret[i] = i&1 == 1 ? ret[i-1]+1 : ret[i>>1];
}
*returnSize = len;
return ret;
}