1. 程式人生 > >338. 位元位計數 Counting Bits

338. 位元位計數 Counting Bits

給定一個非負整數 num。對於 0 ≤ i ≤ num 範圍中的每個數字 ,計算其二進位制數中的 1 的數目並將它們作為陣列返回。

示例 1:

輸入: 2
輸出: [0,1,1]

示例 2:

輸入: 5
輸出: [0,1,1,2,1,2]

進階:

  • 給出時間複雜度為O(n*sizeof(integer))的解答非常容易。但你可以線上性時間O(n)內用一趟掃描做到嗎?
  • 要求演算法的空間複雜度為O(n)
  • 你能進一步完善解法嗎?要求在C++或任何其他語言中不使用任何內建函式(如 C++ 中的 __builtin_popcount)來執行此操作。

解法一:

一個一個地遍歷求解,先考慮如何求一個數n的二進位制數的1的個數,有兩種方法

1.用一個flag初始值為1,把它和n做&運算,如果不為0說明最右端是1,然後把flag左移一位,再去判斷i的倒數第二位,這樣下去直到flag移成0.

unsigned int flag = 1;
        int count = 0;
        while(flag)
        {
            if(flag & n)
            {
                count++;
            }

                flag = flag << 1;

        }

2.用n & (n-1),思想是一個數n和n-1做&運算會把n的最右邊那個1變成0,一個數有多少個1就要做多少次這個運算

class Solution {
public:
    vector<int> countBits(int num) {
        vector<int> ans;
        for(int i = 0; i <= num; ++i)
        {
            ans.push_back(bitNum(i));
        }
        return ans;
    }
    
    int bitNum(int i)
    {
        int count = 0;
        while(i)
        {
            count++;
            i = i & (i - 1);
        }
        return count;
    }
};

解法二:要在O(n)的時間複雜度完成,那肯定得用dp,也就是找規律

0 0

1 1

2 10

3 11

4 100

5 101

6 110

7 111

可以看出一個偶數和一個奇數是一對,且奇數的1個數比偶數1個數多1,並且對與對之間也有關係,一個對整體比一個對的一半多1,如111和11,110和10

那麼可以得到狀態方程ans[i] = ans[i/2]+i%2;

class Solution {
public:
    vector<int> countBits(int num) {
        vector<int> ans;
        ans.push_back(0);
        for(int i = 1; i <= num; ++i)
        {
            ans.push_back(ans[i>>1]+i%2);
        }
        return ans;
    }
    
};

解法三:

用內建函式__builtin_popcount(n)

class Solution {
public:
    vector<int> countBits(int num) {
        vector<int> ans;
        ans.push_back(0);
        for(int i = 1; i <= num; ++i)
        {
            ans.push_back(__builtin_popcount(i));
        }
        return ans;
    }
    
};