[leetcode] Counting Bites

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下,发现确实是对的。。

原文地址:https://www.cnblogs.com/boris1221/p/9313668.html