Description:
Given a non negative integer number num. For every numbers i in the range 0 ≤ i ≤ num calculate the number of 1's in their binary representation and return them as an array.
Example 1:
Input: 2
Output: [0,1,1]
Example 2:
Input: 5
Output: [0,1,1,2,1,2]
Follow up:
- It is very easy to come up with a solution with run time O(n*sizeof(integer)). But can you do it in linear time O(n) /possibly in a single pass?
- Space complexity should be O(n).
- Can you do it like a boss? Do it without using any builtin function like __builtin_popcount in c++ or in any other language.
题目大意:计算0-num中每个数所对应的二进制中1的个数。
方法一:最简单粗暴,如果知道Java有相应API可以直接使用。
class Solution {
public int[] countBits(int num) {
int[] arr = new int[num+1];
for(int i=0;i<num+1;i++){
arr[i] = Integer.bitCount(i);
}
return arr;
}
}
Integer.bitCount(int i)的源码如下,有兴趣的可以研究一下:
/**
* Returns the number of one-bits in the two's complement binary
* representation of the specified {@code int} value. This function is
* sometimes referred to as the <i>population count</i>.
*
* @return the number of one-bits in the two's complement binary
* representation of the specified {@code int} value.
* @since 1.5
*/
public static int bitCount(int i) {
// HD, Figure 5-2
i = i - ((i >>> 1) & 0x55555555);
i = (i & 0x33333333) + ((i >>> 2) & 0x33333333);
i = (i + (i >>> 4)) & 0x0f0f0f0f;
i = i + (i >>> 8);
i = i + (i >>> 16);
return i & 0x3f;
}
方法二:如果不知道API呢,是不是就没有简单的解法呢?当然不是。这道题目的标签是Dynamic Programming,如果不使用一点动态规划,是不是有点对不起命题人的良苦用心呢?
乍眼一看,一脸懵逼,这和动态规划根本就是驴头不对马嘴,没有一毛钱的关系啊?举个例子就明白:
十进制 | 二进制 |
100 | 1100100 |
101 | 1100101 |
50 | 110010 |
观察上面表格中的内容,1100100(100的二进制)、1100101(101的二进制)去掉最后一位,则惊奇的等于110010(100/2=50的二进制)。
其实,这并不是什么秘密。想想十进制,设一个数为x,100,101,102,~109去掉最后一位,也等于 10(x / 10的十进制),这不是同样的道理吗?
那么,i的二进制表示中由多少个1 = i的二进制表示中去掉最后一位以后1的个数 + i的二进制表示中最后一位1的个数
设:f[i]表示i的二进制表示中有多少个1,则有:
f[i] = f[i >> 2] + (i % 2)
即:本动态规划的动态转移方程。
显然本题初始条件为f(0) = 0;可以从0到num的顺序进行动态规划,下面直接看代码:
class Solution {
public int[] countBits(int num) {
int[] dp = new int[num + 1];
for (int i = 1; i < num + 1; i++) {
dp[i] = dp[i >> 1] + (i % 2);
}
return dp;
}
}
这也完全符合题目Follow Up的要求,一次循环完成,线性时间复杂度O(n),空间复杂度 O(n)。