原题
L0338.比特位计算
给你一个整数 n ,对于 0 <= i <= n 中的每个 i ,计算其二进制表示中 1 的个数 ,
返回一个长度为 n + 1 的数组 ans 作为答案。
-
输入:n = 2
-
输出:[0,1,1]
- 来源:力扣(LeetCode)
- 难度:简单
- 链接:https://leetcode-cn.com/problems/counting-bits/
解法
这类题看似简单,但是在我们做出来的基础上,其实还有更高效的解法,比如我一开始也没过多思考,直接暴力解答
public int[] countBits(int n) {
int[] ans = new int[n+1];
for(int i=1,j=0;i<=n;i++){
int re = i;
int res=0;
while(re!=0){
if(re%2!=0){
res+=1;
}
re = re/2;
}
ans[j++]=res;
}
return ans;
}
这样结果是正确的,但是时间复杂度和空间复杂度都很差。
高效解法:
方式一:动态规划——最低有效位
- i&1 求得i的最低位是否为1或者0;
- 对于正整数 x,将其二进制表示右移一位,等价于将其二进制表示的最低位去掉
- 得出:如果x为偶数:bits[x] = bit[x/2]
如果x为奇数:bits[x] =bits[x/2]+1 - 所以 bits[x] = bit[x/2]+x/2的余数 i&1
public int[] countBit(int n){
int[] ans = new int[n+1];
for(int i=1;i<=n;i++){
ans[i] = ans[i>>1]+(i&1);//i>>1去掉最低位,i&1是计算最低位是1还是0
}
return ans;
}
方式二:Brian Kernighan 算法
Brian Kernighan 算法的原理是:
- 对于任意整数 xx,令 x=x&(x-1)x,该运算将 x 的二进制表示的最后一个 1 变成 0
public int[] countBit2(int n){
int[] ans = new int[n+1];
for(int i=0;i<=n;i++){
ans[i] = countOne(i);
}
return ans;
}
public int countOne(int x){
int count=0;
while(x>0){//直到x中没有1 ,也就是为0
x&=(x-1);//Brian Kernighan 算法,将最后一个1变为1
count++;
}
return count;
}