目录
1.题目描述:
给你一个整数 n
,对于 0 <= i <= n
中的每个 i
,计算其二进制表示中 1
的个数 ,返回一个长度为 n + 1
的数组 ans
作为答案。
示例 1:
输入:n = 2 输出:[0,1,1] 解释: 0 --> 0 1 --> 1 2 --> 10
2.解法一:Brian Kernighan 算法
Brian Kernighan算法介绍:
简单来说就是对一个整数二进制数的最后一个1进行操作,有两种表示方式:
第一种:n&(n-1) 可以将n二进制数的最后一个1变为0
如图,计算结果将7最后的一位1变成了0.
第二种:n&(~n+1) 可以得到n二进制最后一个1对应的值
如图,计算结果获得了7最后一个1对应的值“1”.
所以根据Brian Kernighan算法,我们可以每次循环都将n的最后一位变成0,直至n等于0结束循环;或者每次循环n减去获取到的最后一个1对应的值,直至n等于0。最后记录出循环的次数就是1的个数!
代码实现n&(n-1):
public int[] countBits(int n) {
int[] res = new int[n+1];
for (int i=0;i<=n;i++){
res[i] = count(i);
}
return res;
}
public int count(int num){
int times = 0;
while(num!=0){
num = num&(num-1);//每次将num的最后一个1变成0
times ++;//记录变换的次数就是1的个数
}
return times;
}
代码实现n&(~n+1):
public int[] countBits(int n) {
int[] res = new int[n+1];
for (int i=0;i<=n;i++){
res[i] = count(i);
}
return res;
}
public int count(int num){
int times = 0;
while(num!=0){
num -= num&(~num+1);//只有这里修改了,其他和上面一样
times ++;
}
return times;
}
3.解法二:找规律
对于二进制数我们可以找到以下规律:
当n为奇数时 0 -》 0 1 -》 1 2 -》 10 3 -》 11 4 -》 100 5 -》 101 count(n) == count(n-1)-1 当n为偶数时 1 -》 1 2 -》 10 4 -》 100 8 -》 1000 16 -》 10000 count(n) == count(n/2)
当n为奇数时,n中1的个数等于(n-1)中1的个数加1;当n为偶数时,n中1的个数等于n/2中1的个数。
通过这一规律我们可以得到这题的解法。
代码实现如下:
public static int[] countBits1(int n) {
int[] res = new int[n+1];
res[0] = 0;
for (int i = 1;i <= n;i ++){
if(i%2==1){//是奇数
res[i] = res[i-1]+1;
}else {//是偶数
res[i] = res[i/2];
}
}
return res;
}
ok!结束!
参考题解: