方式一:
最容易想到的,代码:
class Solution {
public int[] countBits(int n) {
int[] ans = new int[n+1];
for(int i=0;i<=n;i++){
ans[i]= Integer.bitCount(i);
}
return ans;
}
}
方式二:
对于所有的数字,只有两类:
- 1、奇数:二进制表示中,奇数一定比前面那个偶数多一个 1,因为多的就是最低位的 1。
举例:
0 = 0 1 = 1
2 = 10 3 = 11
- 2、偶数:二进制表示中,偶数中 1 的个数一定和除以 2 之后的那个数一样多。因为最低位是 0,除以 2 就是右移一位,也就是把那个 0 抹掉而已,所以 1 的个数是不变的。
举例:
2 = 10 4 = 100 8 = 1000
3 = 11 6 = 110 12 = 1100
另外,0 的 1 个数为 0,于是就可以根据奇偶性开始遍历计算了。
代码如下:
class Solution {
public int[] countBits(int n) {
int[] ans = new int[n+1];
ans[0] = 0;
for(int i =1;i<=n;i++){
if(i%2 == 1){
ans[i] = ans[i-1] +1;
}else{
ans[i] = ans[i/2];
}
}
return ans;
}
}
方式三
Brian Kernighan 算法
-
最直观的做法是对从
0到n的每个整数直接计算「一比特数」。每个int 型的数都可以用32位二进制数表示,只要遍历其二进制表示的每一位即可得到1的数目。 -
利用
Brian Kernighan算法,可以在一定程度上进一步提升计算速度。Brian Kernighan 算法的原理是:对于任意整数x,令x=x & (x−1),该运算将x的二进制表示的最后一个1变成0。因此,对x重复该操作,直到x变成0,则操作次数即为x的「一比特数」。 -
对于给定的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;
}
}
97

被折叠的 条评论
为什么被折叠?



