338. Counting Bits

来源:互联网 发布:湖北地税网络纳税 编辑:程序博客网 时间:2024/06/03 21:11

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:
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.

Solution:

1. An easy recurrence for this problem is f[i] = f[i / 2] + i % 2.

public int[] countBits(int num) {    int[] f = new int[num + 1];    for (int i=1; i<=num; i++) f[i] = f[i >> 1] + (i & 1);    return f;}


2. O(n) time and space complexity:

class Solution {public:    vector<int> countBits(int num) {        vector<int> ret(num+1, 0);        for (int i = 1; i <= num; ++i)            ret[i] = ret[i&(i-1)] + 1;        return ret;    }};

3. Thinking:

  1. We do not need check the input parameter, because the question has already mentioned that the number is non negative.

  2. How we do this? The first idea come up with is find the pattern or rules for the result. Therefore, we can get following pattern

Index : 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

num : 0 1 1 2 1 2 2 3 1 2 2 3 2 3 3 4

Do you find the pattern?

Obviously, this is overlap sub problem, and we can come up the DP solution. For now, we need find the function to implement DP.

dp[0] = 0;

dp[1] = dp[0] + 1;

dp[2] = dp[0] + 1;

dp[3] = dp[1] +1;

dp[4] = dp[0] + 1;

dp[5] = dp[1] + 1;

dp[6] = dp[2] + 1;

dp[7] = dp[3] + 1;

dp[8] = dp[0] + 1;
...

This is the function we get, now we need find the other pattern for the function to get the general function. After we analyze the above function, we can get
dp[0] = 0;

dp[1] = dp[1-1] + 1;

dp[2] = dp[2-2] + 1;

dp[3] = dp[3-2] +1;

dp[4] = dp[4-4] + 1;

dp[5] = dp[5-4] + 1;

dp[6] = dp[6-4] + 1;

dp[7] = dp[7-4] + 1;

dp[8] = dp[8-8] + 1;
..

Obviously, we can find the pattern for above example, so now we get the general function

dp[index] = dp[index - offset] + 1;

Coding:

public int[] countBits(int num) {    int result[] = new int[num + 1];    int offset = 1;    for (int index = 1; index < num + 1; ++index){        if (offset * 2 == index){            offset *= 2;        }        result[index] = result[index - offset] + 1;    }    return result;}

4. 

This uses the hint from the description about using ranges. Basically, the numbers in one range are equal to 1 plus all of the numbers in the ranges before it. If you write out the binary numbers, you can see that numbers 8-15 have the same pattern as 0-7 but with a 1 at the front.

My logic was to copy the previous values (starting at 0) until a power of 2 was hit (new range), at which point we just reset the t pointer back to 0 to begin the new range.

public int[] countBits(int num) {    int[] ret = new int[num+1];    ret[0] = 0;    int pow = 1;    for(int i = 1, t = 0; i <= num; i++, t++) {        if(i == pow) {            pow *= 2;            t = 0;        }        ret[i] = ret[t] + 1;    }    return ret;}


5.

My Naive Solution;

class Solution {public:    vector<int> countBits(int num) {        vector<int> v;        int temp = 0;        for(int i = 0; i <= num; i++){            temp = i;            temp = ((temp & 0xAAAAAAAA) >> 1) + (temp & 0x55555555);            temp = ((temp & 0xCCCCCCCC) >> 2) + (temp & 0x33333333);            temp = ((temp & 0xF0F0F0F0) >> 4) + (temp & 0x0F0F0F0F);            temp = ((temp & 0xFF00FF00) >> 8) + (temp & 0x00FF00FF);            temp = ((temp & 0xFFFF0000) >> 16) + (temp & 0x0000FFFF);            v.push_back(temp);        }        return v;    }};

Summary:

位运算真的很神奇。










原创粉丝点击