Leetcode: 338.Counting Bits
題目講的是:給定一個數字,按順序輸出範圍[0,n]之間的所有整數的二進制表示中1的個數。
粗暴的做法是,歷遍[0,n]。對每一個數字轉化成二進制,然後一位一位地數。這個複雜度是O(n*sizeof(integer))。
題目當然想我們快點啦。希望我們在O(n)複雜度裏面解決。所以是用的DP。找一下規律。我找到的規律是:
if(i%2)
{
dp.push_back(dp[i/2]+1);
}
else
{
dp.push_back(dp[i/2]);
}
解釋一下,就是以0-1,2-3,4-7,8-15這樣區間去考慮,發現偶數和/2的一致,奇數等於/2+1。
代碼
這樣就可以寫了:
class Solution {
public:
vector<int> countBits(int num)
{
vector<int> dp;
if(num == 0)
{
dp.push_back(0);
return dp;
}
dp.push_back(0);
dp.push_back(1);
if(num == 1)
return dp;
for(int i=2;i<=num;i++)
{
if(i%2)
{
dp.push_back(dp[i/2]+1);
}
else
{
dp.push_back(dp[i/2]);
}
}
return dp;
}
};
按位與方法
看到我的方法打敗了85%的朋友,很高興地點開了discuss。結果發現leetcode網友打代碼還是剛,一把梭。都開始比較誰寫得短了……我看了一下,方法有所不同,比我這個深奧一些,總結一下就是: ret[i] = ret[i&(i-1)] + 1;
這個方程比較難理解,稍微寫一下之後,大概整理思路如下:
拿到一個數n,設其表示爲1100。現在希望用dp來解決,即用前面已經算出了的值來得到後面的值。那麼發現dp[1100]應該是dp[1000]+1。只需要去掉一個低位的1就可以了,那麼i&(i-1)這個就可以保證去掉一個低位的1(i>=1 )。所以……就可以了。
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;
}
};