题目及测试
package pid338;
/* 338. 比特位计数给定一个非负整数 num。对于 0 ≤ i ≤ num 范围中的每个数字 i ,计算其二进制数中的 1 的数目并将它们作为数组返回。示例 1:输入: 2
输出: [0,1,1] 0 01 10示例 2:输入: 5
输出: [0,1,1,2,1,2] 0 01 10 11 100 101 110 111进阶:给出时间复杂度为O(n*sizeof(integer))的解答非常容易。但你可以在线性时间O(n)内用一趟扫描做到吗?要求算法的空间复杂度为O(n)。你能进一步完善解法吗?要求在C++或任何其他语言中不使用任何内置函数(如 C++ 中的 __builtin_popcount)来执行此操作。*/
public class main {public static void main(String[] args) {int[] testTable = {2,5};for (int i=0;i<testTable.length;i++) {test(testTable[i]);}}private static void test(int ito) {Solution solution = new Solution();int[] rtn;long begin = System.currentTimeMillis();System.out.print(ito+" ");System.out.println();rtn = solution.countBits(ito);//执行程序long end = System.currentTimeMillis(); System.out.println("rtn=" );for (int i = 0; i < rtn.length; i++) {System.out.print(rtn[i]+" ");}//打印结果几数组System.out.println();System.out.println("耗时:" + (end - begin) + "ms");System.out.println("-------------------");}}
解法1(成功,2ms,较快)
可以看0-1与2-3
00 01
10 11
可以看到2-3就是在0-1的前面加了个1,所以num[2]=num[0]+1,num[3]=num[1]+1
000 001 010 011 100 101 110 111
可以看到4-7同样也是比0-3每个都多了一个1
可以认为num[i]=num[i-size]+1 size为刚刚小于等于i的2^n
这种方法实际是动态规划 + 最高有效位(与其他结果的最高有效位不同)
package pid338;class Solution {public int[] countBits(int num) {if(num == 0){return new int[]{0};}if(num == 1){return new int[]{0,1};}if(num == 2){return new int[]{0,1,1};}if(num == 3){return new int[]{0,1,1,2};}// 处理>=4的情况int[] result = new int[num+1];result[0] = 0;result[1] = 1;result[2] = 1;result[3] = 2;int size = 4;for(int i=4;i<=num;i++){result[i] = result[i-size]+1;if(i == size * 2 - 1){size = size * 2;}}return result;}
}
解法2(别人的)
遵循上一方法的相同原则,我们还可以通过最低有效位来获得状态转移函数。
观察x 和 x′=x/2 的关系:
x=(1001011101)2=(605)10
x′=(100101110)2=(302)10
可以发现 x′ 与 x 只有一位不同,这是因为x′ 可以看做 x 移除最低有效位的结果。
这样,我们就有了下面的状态转移函数:
P(x)=P(x/2)+(xmod 2)
public class Solution {public int[] countBits(int num) {int[] ans = new int[num + 1];for (int i = 1; i <= num; ++i)ans[i] = ans[i >> 1] + (i & 1); // x / 2 is x >> 1 and x % 2 is x & 1return ans;}
}
解法3(别人的)
动态规划 + 最后设置位
与上述方法思路相同,我们可以利用最后设置位。
最后设置位是从右到左第一个为1的位。使用 x &= x - 1 将该位设置为0,就可以得到以下状态转移函数:
P(x)=P(x&(x?1))+1;
public class Solution {public int[] countBits(int num) {int[] ans = new int[num + 1];for (int i = 1; i <= num; ++i)ans[i] = ans[i & (i - 1)] + 1;return ans;}
}