338. Counting Bits题目详解

题目详情

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.

分析

解法1 —— 直接求解

当然最简单的做法就是遍历1-n,然后每个数字直接求其1的数字,这样复杂度变成了O(nlogn)
这里就不给出具体代码了

解法2 —— 动态规划问题

我们可以把求某个数的1的个数,写出一个递推式
定义re 为返回的数组, 则re[i] 就表示 i的二进制表示中的1的个数,我们把i的二进制表示分成两段,一段为前n - 1位, 另一段为 最右边一位。
所以得到 re[i] = 前n-1位中的1的个数 + i%2
而 前n-1位中1的个数可以用re数组的一个元素来表示, 也就是re[i >> 1]

所以得到递归式子

re[i] = re[i>>1] + i%2;

然后循环 把re的所有项都得到。解法1之所以复杂度高是因为每次算1的个数的时候重复计算了前面的1的个数, 而动态规划里把前面数字的1的个数都记录下来,避免了重复计算, 但是这也要求需要一个数组来存储结果, 这是通过牺牲空间来换取时间的一种策略

代码如下:

class Solution {
public:
    vector<int> countBits(int num) {
        vector <int> re(num+1, 0);

        for (int i = 0; i <= num; i++) {
            re[i] = re[i>>1] + i%2;

        }

        return re;        
    }
};

解法3

这是最快的一种解法

/* 
        Dynamic programming 
        Reoccurence relation:
                dp[i] = dp[i & (i - 1)]] + 1 where i & (i - 1) erases right most bit
                i & -i gives rightmost bit => i - (i & -i) erases rightmost bit
        O(n)
*/

class Solution {
public:
    vector<int> countBits(int num) {
        vector<int> dp(num + 1, 0);

        for (int i = 1; i < num + 1; ++i) {
            dp[i] = dp[i & (i - 1)] + 1;
        }

        return dp;
    }
};
posted @ 2018-09-12 13:03  qq874455953  阅读(102)  评论(0编辑  收藏  举报