每日一题:338. 比特位计数

110 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的11天,点击查看活动详情

一、题目描述:

338. 比特位计数 - 力扣(LeetCode)

给你一个整数 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 <= 10^5  

进阶:

  • 很容易就能实现时间复杂度为 O(n log n) 的解决方案,你可以在线性时间复杂度 O(n) 内用一趟扫描解决此问题吗?
  • 你能不使用任何内置函数解决此问题吗?(如,C++ 中的 __builtin_popcount )

二、思路分析:

理论上是动态规划,但我说不太清楚,因为是找规律得到的,这个题就是个打表题。

  • 因为都是从0开始的,所以最终返回的数组中第一个数字是0。这个数组的生成方法是:逐渐将数组长度加倍,通过将数组原来的每个元素+1,直接放在原数组后面达到长度加倍的效果;
  • 举个例子:
  • 一开始是数组长度为1:{0};将原数组{0}中所有元素+1后得到{1},将{0}和{1}拼接到一起得到{0,1};
  • 数组长度为2:{0,1},所有元素+1得到{1,2},拼接后为{0,1,1,2};
  • 依次类推长度为8时为{0,1,1,2,1,2,2,3}
  • ......

三、AC 代码:

class Solution {
public:
    vector<int> countBits(int n) {
        vector<int> result(n+1);
        result[0] = 0;
        int base = 1;
        for(int i = 1; i <= n; i++){
            result[i] = result[i - base] + 1;
            if(base * 2 == i + 1) base *= 2;
        }
        return result;
    }
};

四、参考:

直观思路:每次到2的幂时,忽略最高位,则是在重复前面所有数 - 比特位计数 - 力扣(LeetCode)

动态规划+位运算[时间复杂度O(n),Java用时1ms][时间复杂度O(n),Java用时1ms] - 比特位计数 - 力扣(LeetCode)