问题描述
给定一个非负整数 num。对于 0 ≤ i ≤ num 范围中的每个数字 i ,计算其二进制数中的 1 的数目并将它们作为数组返回。
示例 1:
输入: 2
输出: [0,1,1]
示例 2:
输入: 5
输出: [0,1,1,2,1,2]
进阶:
给出时间复杂度为O(n*sizeof(integer))的解答非常容易。但你可以在线性时间O(n)内用一趟扫描做到吗?
要求算法的空间复杂度为O(n)。
你能进一步完善解法吗?要求在C++或任何其他语言中不使用任何内置函数(如 C++ 中的 __builtin_popcount)来执行此操作。
解题思路
数字每%2如果为0则最后一位就是0,不为0则该位上为1,不断数字/2,直到为0,记录1的个数
实现
class Solution {
public int[] countBits(int num) {
int[] res=new int[num+1];
for(int i =0;i<=num;i++){
int n = 0;
int tem=i;
while(tem>0){
if(tem%2!=0){
n++;
}
tem=tem/2;
}
res[i]=n;
}
return res;
}
}
其他思路
2,4,8时候,即2的幂的时候只有一个1,则3=2+1,就是2中1的个数加上1中1的个数,再如10=8+2,则8中1的个数为1,2中1的个数为1,最终为2个1
实现2
对于求解一个十进制数转化为二进制时里面1的个数,可以先看一下概况:
十进制数 二进制数 1的个数
1 1 1
2 10 1
3 11 2
4 100 1
5 101 2
6 110 2
7 111 3
1:问题归纳:用数组a[ i ] 表示 i 的二进制中1的个数。
2:递推关系式 a[n] = a[n/2] n为偶数
a[n] = a[n-1] +1 n为奇数
3:初始化:a[0] = 0
把数分奇数和偶数来分别判断:
偶数:偶数 i 中1的个数跟i/2中1的个数是相同的
奇数:偶数+1,奇数最后一位一定是1
public class CountBits {
public int[] countBits(int num) {
int[] res=new int[num+1];//a[0] = 0
int n = num%2==0?num:num-1;//把传进来的值固定为偶数,这样就能判断遍历的值,每一个的奇偶性(固定为奇数也可,这里的目标是知道用的每个数的奇偶)
for(int i=1;i<=n;++i){
res[i]=res[(i-1)/2]+1;//奇数
i++;//加1,变偶数
res[i]=res[i/2];//偶数
}
if(n<num){//如果开始传的是奇数,把最后一个加进来
res[num]=res[(num-1)/2]+1;
}
return res;
}
}
实现3
public int[] countBits1(int num) {
int[] res = new int[num+1];
for(int i=1;i<=num;i++){
res[i]=res[i&(i-1)]+1;
}
return res;
}
对于: res[i]=res[i&(i-1)]+1
奇数:i&(i-1)=i-1(奇数到小于它的偶数,没有进位,只差1,也就是二进制的最后以为,1&0=0,即为它的偶数)
偶数:偶数&小于它的奇数,会有进位,当i&(i-1)时,剩下的就是它除了进位那个1以外的数,该数中的1的个数再加上进位的1就是最终它1的个数。