題目來源:力扣
題目描述:
給定一個非負整數 num。對於 0 ≤ i ≤ num 範圍中的每個數字 i ,計算其二進制數中的 1 的數目並將它們作爲數組返回。
================================================
示例 1:
輸入: 2
輸出: [0,1,1]
示例 2:
輸入: 5
輸出: [0,1,1,2,1,2]
=============================================
給出時間複雜度爲O(n*sizeof(integer))的解答非常容易。但你可以在線性時間O(n)內用一趟掃描做到嗎?
審題:
最簡單的方法是檢查每一整數的比特位,計算爲1的個數.此處我們考慮其他時間複雜度更小的方法.
首先觀察連續整數的比特數組,{0, 1, 10, 11, 100, 101, 110, 111},觀察以上序列我們可以發現如下規律,2的比特位中1的個數等於0的比特位中1的個數+1,3的比特位中1的個數等於1的比特位中1的個數+1,4的比特位中1的個數等於0的比特位中1的個數+1,5的比特位中1的個數等於1的比特位中1的個數+1.我們使用表示整數i中比特位爲1的個數,則可以推導出如下公式:
,且.
基於以上最優子結構推導,我們可以使用動態規劃算法自底向上依次計算S[0], S[1], …S[n].
還有另一中更簡潔的方法,在看了此方法後,深感巧妙.所有整數可分爲奇數和偶數兩種,如果一個數是奇數,則其前一個數是偶數,並且該奇數位爲1的個數等於前一偶數位爲1個數加1,因爲相較於前一偶數,除最低位由0變爲1外,其餘位均相同.如果當前數爲偶數,則該偶數中位爲1的個數等於該偶數除以2對應偶數中位爲1的個數,因爲除以2相當於將當前偶數右移一位,由於右移的最低位爲0,因此移位後整數爲1的個數不變.我們可以推導出如下最優子結構:
java算法:
class Solution {
public int[] countBits(int num) {
if(num == 0)
return new int[]{0};
int[] S = new int[num+1];
S[0] = 0;
S[1] = 1;
for(int i = 2; i <= num; i++){
int mod = (int)Math.pow(2, (int)(Math.log(i) / Math.log(2)));
S[i] = S[i % mod] + 1;
}
return S;
}
}
位運算版本
class Solution {
public int[] countBits(int num) {
if(num == 0)
return new int[]{0};
int[] S = new int[num+1];
S[0] = 0;
S[1] = 1;
for(int i = 2; i <= num; i++)
if((i & 1) == 0)
S[i] = S[i >> 1];
else
S[i] = S[i-1] + 1;
return S;
}
}