比特位计数-记忆化搜索与动态规划
题目描述
338. 比特位计数 难度:中等-简单
给定一个非负整数 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)来执行此操作。
题解
暴力解法
暴力解法很简单,每次逐位扫描,时间复杂度为O(n*sizeof(integer))。
记忆化搜索与动态规划
从0到num统计的过程中,我们会发现:
假设当前的数是100101,很明显去掉最高位的1,数00101的1的位数前面已经统计过了,1得个数只需要再加1即可,类似递归的思想。
因此我们有了以下思路:
假设当前的数是j,
一定存在i,使得 2^i <= j < 2^(i+1)
那么bitsArr[j] = bitArr[j-2^i] + 1。
代码:
1 class Solution { 2 public int[] countBits(int num) { 3 int[] bitsArr = new int[num+1]; 4 bitsArr[0] = 0; 5 if(num>=1){ 6 for(int i=0;(int)(Math.pow(2,i))<=num;i++){ 7 bitsArr[(int)(Math.pow(2,i))]=1; 8 for(int j=(int)(Math.pow(2,i))+1;j<(int)(Math.pow(2,i+1))&&j<=num;j++){ 9 bitsArr[j]=bitsArr[j-(int)(Math.pow(2,i))]+1; 10 } 11 } 12 } 13 return bitsArr; 14 } 15 }
优化
上述解法较多调用了幂运算和int转换,效率较低。下面采用位运算优化。
使用i&(i-1)==0来判断i是否是2的整数幂。
代码:
1 class Solution { 2 public int[] countBits(int num) { 3 int[] bitsArr = new int[num+1]; 4 bitsArr[0] = 0; 5 int powOf2 = 0;//存放2的整数幂 6 for(int i=1;i<=num;i++){ 7 if( (i&(i-1))==0 ){//如果i是2的整数幂 8 powOf2 = i; 9 bitsArr[i] = 1; 10 }else{ 11 bitsArr[i] = bitsArr[i-powOf2] + 1; 12 } 13 } 14 return bitsArr; 15 } 16 }
另解-最低位
上述解法其实是去掉最高位,将低位求解转化为已经求得的数,其实还可以去掉右移一位去掉最低位,转化为已经求得的数,再根据去掉的那一位是0还是1来判断是否额外加1。
代码:
1 class Solution { 2 public int[] countBits(int num) { 3 int[] bitsArr = new int[num+1]; 4 bitsArr[0] = 0; 5 for(int i=1;i<=num;i++){ 6 bitsArr[i] = bitsArr[i>>1] + (i&1); 7 } 8 return bitsArr; 9 } 10 }

浙公网安备 33010602011771号