LeetCode 0338. 比特位计数

Posted Tisfy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode 0338. 比特位计数相关的知识,希望对你有一定的参考价值。

【LetMeFly】338.比特位计数:三种方法求一个数二进制下有多少个1

力扣题目链接:https://leetcode.cn/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

写在前面

本篇题解的三种方法不论哪一种,大致思路就是对于某个数,单独求出其二进制下有多少个1。

每个数的求解是相互独立的,求这一个数的时候没有用到上一个数的结果。

方法一:每次取最低位

对于一个数 n n n,在 n ≠ 0 n\\neq0 n=0时,不断取出当前 n n n的最低位,判断是否为1(KaTeX parse error: Expected 'EOF', got '&' at position 2: n&̲1

之后,将 n n n的最低位丢弃(右移即可, n > > 1 n>>1 n>>1

这样就统计出了 n n n在二进制下有多少个1。

  • 时间复杂度 O ( n log ⁡ 2 n ) O(n\\log_2 n) O(nlog2n)
  • 空间复杂度 O ( 1 ) O(1) O(1),力扣算法答案不计入空间复杂度

AC代码

C++

不为0时取最低位,时间/空间超越:7.24%,55.59%

class Solution 
private:
    int __LetMeFly_popcount(int n) 
        int ans = 0;
        while (n) 
            if (n & 1)
                ans++;
            n >>= 1;
        
        return ans;
    
public:
    vector<int> countBits(int n) 
        vector<int> ans(n + 1);
        for (int i = 0; i <= n; i++) 
            ans[i] = __LetMeFly_popcount(i);
        
        return ans;
    
;

方法二:借助内置函数__builtin_popcount

对于一个数 n n n,我们可以直接使用内置函数__builtin_popcount(n)来求出n在二进制下有多少个1

有些编译器不支持上述操作,但是力扣是支持的

  • 时间复杂度 O ( n log ⁡ 2 n ) O(n\\log_2 n) O(nlog2n)
  • 空间复杂度 O ( 1 ) O(1) O(1),力扣算法答案不计入空间复杂度

AC代码

C++

内置__builtin_popcount,时间/空间超越:83.71%,56.81%

class Solution 
public:
    vector<int> countBits(int n) 
        vector<int> ans(n + 1);
        for (int i = 0; i <= n; i++) 
            ans[i] = __builtin_popcount(i);
        
        return ans;
    
;

方法三:借助lowbit

对于一个数 n n n,我们可以巧妙借助 l o w b i t lowbit lowbit来快速取出 n n n中的1

l o w b i t lowbit lowbit可以在 O ( 1 ) O(1) O(1)的复杂度内求出:一个数二进制下第一个1开始到二进制下最后一位 所组成的数。

说人话就是:

假如 n = 6 ( 11 0 2 ) n=6(110_2) n=6(1102),那么 l o w b i t ( 6 ) lowbit(6) lowbit(6)就等于 1 0 2 10_2 102,也就是十进制下的 2 2 2

这样,每次求得 l o w b i t lowbit lowbit后再减去之,就能每次消灭一个 1 1 1

二进制下有 k k k 1 1 1的一个数 n n n只需要进行 k k k次运算就能求得答案。

具体原理可参考我之前的笔记:https://letmefly.xyz/Notes/ACM/Template/lowbit.html

喜欢了可以给个Star

  • 时间复杂度 O ( n K ) O(n K) O(nK),其中 K K K n n n个数平均的“二进制下1的个数”
  • 空间复杂度 O ( 1 ) O(1) O(1),力扣算法答案不计入空间复杂度

AC代码

C++

借助lowbit,时间/空间超越:83.71%,96.33%

class Solution 
private:
    int __LetMeFly_popcount_byLowbit(int n) 
        int ans = 0;
        while (n) 
            n -= (n & -n);
            ans++;
        
        return ans;
    
public:
    vector<int> countBits(int n) 
        vector<int> ans(n + 1);
        for (int i = 0; i <= n; i++) 
            ans[i] = __LetMeFly_popcount_byLowbit(i);
        
        return ans;
    
;

同步发文于CSDN,原创不易,转载请附上原文链接哦~
Tisfy:https://letmefly.blog.csdn.net/article/details/127087581

以上是关于LeetCode 0338. 比特位计数的主要内容,如果未能解决你的问题,请参考以下文章

Leetcode——338. 比特位计数

LeetCode338. 比特位计数(位运算)

简单动态规划的实现(Leetcode 338. 比特位计数)

leetcode-338. 比特位计数

Leetcode 338. 比特位计数

LeetCode 338. 比特位计数