【刷题笔记】338. 比特位计数

111 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 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 )

二、思路分析:

在写代码之前,我们知道2的次幂都有0,1,2,4,8,16,32,64...,这些数的二进制数都只有1位! 因此,每次我们都利用不大于N的最大二进制1位数。

比如,我们要得到f(6),那么我们就需要f(6)=f(4)+f(2),这里4就是不大于6的最大二进制1位数。

因而,我们设定一个left和right,所有我们要的数都满足:left < N < right。

状态方程就是f(N) = f(left) + f(N - left)

三、AC 代码:

class Solution {
    public int[] countBits(int num) {
        int left = 1;
        int right = 2;
        if(num == 0){
            return new int[]{0};
        }
        if(num == 1){
            return new int[]{0,1};
        }
        int[] arr = new int[num+1];
        arr[0] = 0;
        arr[1] = 1;
        for(int i=2;i<=num;i++){
            if(i == right){
                left *= 2;
                right *= 2;
                arr[i] = 1;
            }
            else{
                arr[i] = arr[i-left] + arr[left];
            }
        }
        return arr;
    }
}

四、参考:

每日一题题解——无位运算的简单暴力解法 - 比特位计数 - 力扣(LeetCode)

利用lowerbit(k&(-k))的思路 - 比特位计数 - 力扣(LeetCode)

对二取余方式,简单易懂,不用处理二进制 - 比特位计数 - 力扣(LeetCode)