LeetCode338. 比特位计数

Posted ZSYL

tags:

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

question

给定一个非负整数 num。对于 0 ≤ i ≤ num 范围中的每个数字 i ,计算其二进制数中的 1 的数目并将它们作为数组返回。

示例 1:

输入: 2
输出: [0,1,1]

bitCount()

这道题需要计算从 0 到 n 的每个整数的二进制表示中的 1 的数目。

部分编程语言有相应的内置函数用于计算给定的整数的二进制表示中的 1 的数目,例如 JavaInteger.bitCount()

class Solution {
    public int[] countBits(int n) {
        int[] x = new int[n+1];
        for(int i = 0; i <= n; i++) {
            x[i] = Integer.bitCount(i);
        }
        return x;
    }
}

Brian Kernighan 算法

最直观的做法是对从 0 到 n 的每个整数直接计算「一比特数」。每个 int 型的数都可以用 32 位二进制数表示,只要遍历其二进制表示的每一位即可得到 1 的数目。

利用 Brian Kernighan 算法,可以在一定程度上进一步提升计算速度。Brian Kernighan 算法的原理是:对于任意整数 x,另 x=x&(x-1),该运算将x的二进制表示的最后一个1变成0,对该x重复该操作,直到x为0,统计操作次数。

对于给定的 n,计算从 0 到 n 的每个整数的「一比特数」的时间都不会超过 O(logn),因此总时间复杂度为 O(nlogn)。

class Solution {
    public int[] countBits(int n) {
        int[] bits = new int[n + 1];
        for (int i = 0; i <= n; i++) {
            bits[i] = countOnes(i);
        }
        return bits;
    }

    public int countOnes(int x) {
        int ones = 0;
        while (x > 0) {
            x &= (x - 1);
            ones++;
        }
        return ones;
    }
}

时间复杂度:O(nlogn)。需要对从 0 到 n 的每个整数使用计算「一比特数」,对于每个整数计算「一比特数」的时间都不会超过 O(logn)。

空间复杂度:O(1)。除了返回的数组以外,空间复杂度为常数。

最高有效位(DP)

对于正整数 x,如果可以知道最大的正整数 y,使得 y≤x 且 y 是 2 的整数次幂,则 y 的二进制表示中只有最高位是 1,其余都是 0,此时称 y 为 x 的「最高有效位」。令 z=x−y,显然0≤z<x,则 bits[x]=bits[z]+1。

为了判断一个正整数是不是 2 的整数次幂,可以利用方法一中提到的按位与运算的性质。如果正整数y是2的整数幂,则 y 的二进制表示中只有最高位是 1,其余都是 0,因此 y & (y−1)=0。

class Solution {
    public int[] countBits(int n) {
        int[] bits = new int[n + 1];
        int highBit = 0;
        for (int i = 1; i <= n; i++) {
            if ((i & (i - 1)) == 0) {
                highBit = i;
            }
            bits[i] = bits[i - highBit] + 1;
        }
        return bits;
    }
}

复杂度分析

  • 时间复杂度:O(n)。
  • 空间复杂度:O(1)。

最低有效位(DP)

x/2 == x >> 1
x除2的余数==x&1

  • 如果 x 是偶数,bits[x] = bits[x/2];
  • 如果 x 是奇数,bits[x] = bits[x/2]+1;
class Solution {
    public int[] countBits(int n) {
        int[] bits = new int[n + 1];
        for (int i = 1; i <= n; i++) {
            bits[i] = bits[i >> 1] + (i & 1);
        }
        return bits;
    }
}

最低设置位(DP)

y = y&(y-1):则 y 为将 x 的最低设置位从 1 变成 0 之后的数。

因此对任意正整数 i,都有 bits[i] = bits[i & (i - 1)] + 1;

class Solution {
    public int[] countBits(int n) {
        int[] bits = new int[n + 1];
        for (int i = 1; i <= n; i++) {
            bits[i] = bits[i & (i - 1)] + 1;
        }
        return bits;
    }
}

复杂度分析

  • 时间复杂度:O(n).
  • 空间复杂度:O(1)

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

Leetcode——338. 比特位计数

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

leetcode-338. 比特位计数

Leetcode 338. 比特位计数

LeetCode 338. 比特位计数

338.比特位计数( Counting Bits)leetcode