题目
给你一个整数 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 算法计算 一比特数 。该算法的原理是:
x & (x-1)会去掉x二进制中的最后一个1。- 不断执行
x = x & (x-1),直到x为0,执行的次数就是x二进制中1的个数。
function getOneCount(i: number): number {
let count = 0;
while (i > 0) {
count++;
i = i & (i-1);
}
return count;
}
所以,对于本题,遍历 0 到 n 的每一个数,对每一个数执行一次 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)。