「力扣338」比特位计数

43 阅读1分钟

题目

给你一个整数 n ,对于 0 <= i <= n 中的每个 i ,计算其二进制表示中 1 的个数 ,返回一个长度为 n + 1 的数组 ans 作为答案。

原题链接

比特位计数

思路1

遍历 0 <= i <= n 的每个 i ,利用 辗转相除法 计算每一个 i 的二进制字符串,同时统计字符串的1的个数,然后放入 ans 中,返回 ans 即可。

代码

TypeScript

function countBits(n: number): number[] {
    const ans = [];
    for (let i = 0; i <= n; i++) {
        ans.push(getOneCount(getBits(i)));
    }
    return ans;
};

// 计算二进制字符串中`1`的个数
function getOneCount(bits: string) {
    let count = 0;
    for (const letter of bits) {
        if (letter === '1') {
            count++;
        }
    }
    return count;
}


// 返回如`1001`这样的二进制字符串
function getBits(n: number): string {
    if (n === 0) {
        return '0';
    }

    let remainders = '';
    while (n !== 0) {
        remainders = (n % 2) + remainders;
        n = Math.floor(n / 2);
    }
    return remainders;
}

思路2

通过 Brian Kernighan 算法计算 一比特数 。该算法的原理是:

  1. x & (x-1) 会去掉 x 二进制中的最后一个 1
  2. 不断执行 x = x & (x-1),直到 x0,执行的次数就是 x 二进制中 1 的个数。
function getOneCount(i: number): number {
    let count = 0;
    while (i > 0) {
        count++;
        i = i & (i-1);
    }
    return count;
}

所以,对于本题,遍历 0n 的每一个数,对每一个数执行一次 Brian Kernighan 算法,把结果存放到同一个数组里,返回这个数组即可。

代码

TypeScript

function countBits(n: number): number[] {
    const ans = [];
    for (let i = 0; i <= n; i++) {
        ans.push(getOneCount(i));
    }
    return ans;
};


function getOneCount(i: number): number {
    let count = 0;

    while (i > 0) {
        count++;
        i = i & (i-1);
    }

    return count;
}

C++

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

    int getOneCount(int i) {
        int count = 0;
        while (i > 0) {
            count++;
            i = i & (i-1);
        }
        return count;
    }
};

复杂度

时间复杂度

遍历需要 O(N) 的时间复杂度,而对于每一个数,计算「一比特数」的时间不会超过 O(logN),所以最终的时间复杂度是 O(NlogN)

额外空间复杂度

返回的 ans 不算在额外空间复杂度中,所以只用了有限的几个变量,额外空间复杂度O(1)