題目大意
給一個整數n,計算0~n每個數的二進制表示中1出現的次數。
輸入
整數n,輸出一個列表。例如輸入5,輸出[0,1,1,2,1,2]
,分別表示0,1,2,3,4,5每個數的二進制表示中1出現的次數。
要求: 時間、空間複雜度都爲O(n)
思路
二進制相關題目中有一個經常用到的一個技巧,x & -x
,表示x的二進制表示中最後一個1出現的位置往後組成的數。例如x=11011100
,那麼x & -x = 100
。那麼x - (x & -x)
剛好比x
的二進制表示少一個1。所以對於數x,可以確定x二進制表示中1出現的次數times[x] = times[x - (x & -x)] + 1
。
不難想到對於奇數x來說,它的二進制表示中1出現的次數等於x-1
中1的次數再加1,即times[x] = times[x - 1] + 1
。當然也可以按照上面的方法計算,實際上是一樣的: x - (x & -x) = x - 1, (x % 2 == 1)
。
由此,可以使用遞推的方式,對奇偶數討論,若x爲
- 奇數,則
times[x] = times[x - 1] + 1
- 偶數,則
times[x] = times[x - (x & -x)] + 1
代碼
class Solution {
public:
vector<int> countBits(int num) {
if (num == 0) return {0};
if (num == 1) return {0, 1};
vector<int> dp(num + 1, 0);
dp[0] = 0, dp[1] = 1;
for (int i = 2; i <= num; i++) {
if (i & 1) {
// odd
dp[i] = 1 + dp[i - 1];
} else {
// even
dp[i] = dp[i - (i & -i)] + 1;
}
}
return dp;
}
};
總結
利用(x & -x)
尋找遞推關係。