题目描述:
给定一个非负整数 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)来执行此操作。
代码:
public class LC338 {
//方法一:循环遍历该元素二进制的的32位,统计1的个数,暴力
//时间复杂度O(n*sizeof(Integer))
//空间复杂度O(n)
public int[] countBits(int num) {
int[] bits = new int[num + 1];
for (int i = 0; i <= num; i++){
int cnt = 0;
//tmp的二进制只有一个为1,它代表着2^j
long tmp = 1;
for (int j = 0;j < 32;j++){
//判断i的第j+1(j从0开始)个位置上是否为1,如果是则cnt++
if ((i&tmp)==tmp){
cnt++;
}
tmp=tmp<<1;
}
bits[i] = cnt;
}
return bits;
}
//方法二:dp,最高有效位
//时间复杂度O(n) 空间复杂度O(n)
/*
(1)最高有效位:对于正整数x,如果可以知道最大的正整数y,使得y≤x且y是2的整数次幂,则y的二进制表示中
只有最高位是1,其余都是0,此时成y为x的最高有效位。令z=x-y,显然0≤z<x,则bits[x]=bits[z]+1。
(2)如果一个正数y是2的整数次幂,则y的二进制表示中只有最高位是1,其余都是0,因此y&(y-1)=0.
因此在知道以上两个知识点后我们就可以做如下操作:
操作一:去寻找最高有效位:如果i&(i-1)=0,则就更新当前的最高有效位highBit
操作二:确定当前i的“一比特数”,bits[i] = bits[i-highBit] + 1;
*/
public int[] countBits1(int num){
int[] bits = new int[num + 1];
int highBit = 0;
for (int i = 1; i <= num; i++){
//操作一:寻找最高有效位
if ((i&(i-1)) ==0){
highBit = i;
}
//通过动态转移方程来获取当前的“一比特数”的数量
bits[i] = bits[i - highBit] + 1;
}
return bits;
}
public static void main(String[] args) {
LC338 obj = new LC338();
int[] bits = obj.countBits1(5);
for (int i:bits){
System.out.println(i);
}
}
}