题目
给你一个整数 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)
。