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:
For num = 5
you should return [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.
分析:题目意思很明确,翻译一下:一个数字num,要求找0——num中每个数字的二进制中有多少个1。题目也明确了最容易想到的方法的时间复杂度是O(n*sizeof(integer)),就是一个循环过去,在每个循环里调用一个函数来计算这个数字有多少个1。这个方法就不展示了,代码也很容易写。这里我准备说一下第二个思路,用动态规划。
思路二:动态规划。首先来看一下1——15各个数字的情况:
0 0000 0
-------------
1 0001 1
-------------
2 0010 1
3 0011 2
-------------
4 0100 1
5 0101 2
6 0110 2
7 0111 3
-------------
8 1000 1
9 1001 2
10 1010 2
11 1011 3
12 1100 2
13 1101 3
14 1110 3
15 1111 4
可以确定的是当前状态dp[i]是与前面的状态有关的。我们知道一个正整数n,如何去找状态转移方程呢。考虑位运算,将n的二进制右移一位,那么高位补零,得到一个数字m,那么n二进制中1的个数就比m二进制中1的个数多一个n的最低为是否为1了。状态转移方程如下:dp[i]=dp[i>>1]+i&1;代码如下:
1 class Solution { 2 public int[] countBits(int num) { 3 int[] dp = new int[num+1]; 4 for ( int i = 1 ; i < num+1 ; i ++ ) dp[i]=dp[i>>1]+(i&1); 5 return dp; 6 } 7 }
还有一种动态规划的方法如下:n&(n-1)是用来判断这个数是否是2的指数,若结果为0,就是2的指数。其实n&(n-1)的作用是将n的二进制中最低为改为0。在我们的题目中,状态转移方程为:dp[i]=dp[i&(i-1)]+1。代码就不放上去了,但是我还是没有看懂状态转移方程的联系。不过分析了一i下,发现确实是对的。。