338. 比特位計數(shù) (動態(tài)規(guī)劃)

力扣題解《卑鄙的異鄉(xiāng)人碎乃,巧妙的動態(tài)規(guī)劃(圖解過程))》

方法一:暴力計算

思路

  • 0num 遍歷姊扔,將每一個數(shù)字轉(zhuǎn)換成二進(jìn)制,轉(zhuǎn)換同時計算包含幾個 1
  • 這里采用了模擬短除的方法梅誓,對數(shù)字不斷做除法恰梢,保存余數(shù)佛南,并將數(shù)字用商替換。

復(fù)雜度分析

  • 時間復(fù)雜度 O(N*len(N)):遍歷需要 O(N)嵌言,將每個數(shù)轉(zhuǎn)二進(jìn)制需要 O(len(N))嗅回,其中 len(N) 表示一個十進(jìn)制數(shù)N,轉(zhuǎn)換為二進(jìn)制后的長度呀页。

  • 空間復(fù)雜度 O(N):最終返回的列表需要占用 O(N) 空間

快樂小視頻




具體代碼

class Solution {
public:
    // 搞一個新的函數(shù)妈拌,來將10進(jìn)制轉(zhuǎn)換成2進(jìn)制數(shù)拥坛。
    int trans2bit(int num){
        int ans = 0;
        // 直到num全部轉(zhuǎn)換完成蓬蝶,才退出循環(huán)
        while(num > 0){
            // 判斷當(dāng)前位是0還是1
            // 無論是0還是1都添加到答案中
            ans += num % 2;
            // 不斷除以2,計算下一位
            num /= 2;
        }
        // 返回二進(jìn)制表示時猜惋,1的個數(shù)
        return ans;
    }
    vector<int> countBits(int num) {
        vector<int> ans(num + 1);
        // 0的結(jié)果就是0丸氛,因此從1開始循環(huán)
        for(int i = 1; i <= num; i++){
            ans[i] = trans2bit(i);
        }
        return ans;
    }
};

方法二:簡單的動態(tài)規(guī)劃

思路

  • 這是一道很模板的線性動態(tài)規(guī)劃。個人認(rèn)為線性動態(tài)規(guī)劃就是前人栽樹后人乘涼著摔。每個新結(jié)果的誕生缓窜,都可以依賴于前面已經(jīng)確定的結(jié)果線性變化得出

  • 狀態(tài)定義:

    • dp[i] 表示數(shù)字 i 對應(yīng)的二進(jìn)制表示中 1 的數(shù)量谍咆。
  • 狀態(tài)轉(zhuǎn)移:

    • 當(dāng) i 為偶數(shù)時:由二進(jìn)制表示規(guī)則我們可以知道禾锤,二進(jìn)制表示的最后一位為0,也就是說刪去這個0摹察,對 dp[i] 也不會有任何影響恩掷。因此 dp[i] = dp[i / 2]
    • 當(dāng) i 為奇數(shù)時:由二進(jìn)制表示規(guī)則我們可以知道,二進(jìn)制表示的最后一位為1供嚎,也就是說數(shù)字 i 因為這個1黄娘,比數(shù)字 (i-1)/2 最終結(jié)果多1。因此 dp[i] = dp[(i - 1) / 2] + 1
  • 轉(zhuǎn)移方程
    dp[i] = \left\{\begin{matrix}dp[i/2] \\ dp[(i-1)/2]+1 \end{matrix}\right. \begin{matrix}(i\%2=0) \\ (i\%2=1) \end{matrix}

  • 初始狀態(tài):

    • dp[i] 所有元素置0克滴,當(dāng)計算后才進(jìn)行賦值逼争。
  • 返回值:

    • 返回 dp 列表。

復(fù)雜度分析

  • 時間復(fù)雜度 O(N):遍歷 dp 數(shù)組需要 O(N)劝赔,計算每個 dp[i] 需要 O(1)誓焦。

  • 空間復(fù)雜度 O(N):最終返回的列表需要占用 O(N) 空間

快樂小視頻



具體代碼

class Solution {
public:
    vector<int> countBits(int num) {
        // 預(yù)先開好空間
        vector<int> dp(num + 1);

        // 同樣不需要從0開始,因為dp[0] = 0
        for(int i = 1; i <= num; i++){
            if(i % 2 == 0){ // 偶數(shù)
                dp[i] = dp[i / 2];
            }
            else{ // 奇數(shù)
                dp[i] = dp[(i - 1) / 2] + 1;
            }
        }
        
        // dp數(shù)組即為所求
        return dp;
    }
};

方法三:卑鄙的異鄉(xiāng)人着帽,巧妙的動態(tài)規(guī)劃

思路

  • 這里用到了兩個位運算操作:

    1. x & 1 :用于判斷奇偶性
    2. x & (x-1):用于刪除二進(jìn)制右數(shù)第一個 1

    原理證明1:x1 做按位與罩阵,相當(dāng)于與 000...00001 做按位與,當(dāng) x 為奇數(shù)時启摄,x 的二進(jìn)制末尾為 1 稿壁,此時得到的按位與結(jié)果為 1, 否則的話按位與結(jié)果為 0

    原理證明2:xx-1 做按位與歉备。假設(shè) x 形如 10...1000 的形式傅是。則 x-1 形如 10...0111 ,右數(shù)第一個 1 被借位,變?yōu)?0喧笔。按位與后帽驯,會發(fā)現(xiàn)做到了刪除右數(shù)第一個 1 的效果。

  • 使用位運算x & 1书闸,我們可以替換方法一和方法二中尼变,判斷奇偶的操作。即將所有的x % 2 替換為x & 1浆劲。但需要注意的是嫌术,位運算的優(yōu)先級較低,判斷時需要加括號(x & 1) == 0

  • 使用位運算x & (x-1)牌借,我們可以優(yōu)化方法一中的循環(huán)條件度气,每次刪除最右側(cè)的1,直到數(shù)字變?yōu)?膨报。

  • 使用位運算x & (x-1)磷籍,我們還可以優(yōu)化方法二中的動態(tài)規(guī)劃。由于該位運算的操作效果是刪除二進(jìn)制右數(shù)第一個 1现柠,則顯然處理后的結(jié)果 y 比原結(jié)果 x 要小院领,且二者的關(guān)系滿足 dp[x] = dp[y] + 1

  • 狀態(tài)定義:

    • dp[i] 表示數(shù)字 i 對應(yīng)的二進(jìn)制表示中 1 的數(shù)量。
  • 狀態(tài)轉(zhuǎn)移:

    • 當(dāng) i 為0時:顯然dp[0]=0
    • 當(dāng) i 非0時:按位與之后的結(jié)果够吩,比原數(shù)字的二進(jìn)制值的1的數(shù)目少1比然。因此 dp[i] = dp[i & i - 1)] + 1
  • 轉(zhuǎn)移方程

    • dp[i] = dp[i & (i-1)] + 1
  • 初始狀態(tài):

    • dp[i] 所有元素置0,當(dāng)計算后才進(jìn)行賦值废恋。
  • 返回值:

    • 返回 dp 列表谈秫。

復(fù)雜度分析

  • 時間復(fù)雜度 O(N):遍歷 dp 數(shù)組需要 O(N),計算每個 dp[i] 需要 O(1)鱼鼓。

  • 空間復(fù)雜度 O(N):最終返回的列表需要占用 O(N) 空間

快樂小視頻




具體代碼

  • 方法一優(yōu)化
class Solution {
public:
    // 搞一個新的函數(shù)拟烫,計算數(shù)字num二進(jìn)制表示有幾個1。
    int trans2bit(int num){
        int ans = 0;
        // 直到num位0迄本,才退出循環(huán)
        while(num > 0){
            // num不為零硕淑,說明至少還有一個1
            ans++;
            // 刪去num最右側(cè)的1
            num &= num - 1;
        }
        // 返回二進(jìn)制表示時,1的個數(shù)
        return ans;
    }
    vector<int> countBits(int num) {
        vector<int> ans(num + 1);
        // 0的結(jié)果就是0嘉赎,因此從1開始循環(huán)
        for(int i = 1; i <= num; i++){
            ans[i] = trans2bit(i);
        }
        return ans;
    }
};
  • 方法二優(yōu)化
class Solution {
public:
    vector<int> countBits(int num) {
        // 預(yù)先開好空間
        vector<int> dp(num + 1);

        // 同樣不需要從0開始置媳,因為dp[0] = 0
        for(int i = 1; i <= num; i++){
            // 轉(zhuǎn)移方程:
            dp[i] = dp[i & (i - 1)] + 1;
        }
        
        // dp數(shù)組即為所求
        return dp;
    }
};
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市公条,隨后出現(xiàn)的幾起案子拇囊,更是在濱河造成了極大的恐慌,老刑警劉巖靶橱,帶你破解...
    沈念sama閱讀 217,826評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件寥袭,死亡現(xiàn)場離奇詭異路捧,居然都是意外死亡,警方通過查閱死者的電腦和手機传黄,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評論 3 395
  • 文/潘曉璐 我一進(jìn)店門杰扫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人膘掰,你說我怎么就攤上這事章姓。” “怎么了识埋?”我有些...
    開封第一講書人閱讀 164,234評論 0 354
  • 文/不壞的土叔 我叫張陵凡伊,是天一觀的道長。 經(jīng)常有香客問我惭聂,道長窗声,這世上最難降的妖魔是什么相恃? 我笑而不...
    開封第一講書人閱讀 58,562評論 1 293
  • 正文 為了忘掉前任辜纲,我火速辦了婚禮,結(jié)果婚禮上拦耐,老公的妹妹穿的比我還像新娘耕腾。我一直安慰自己,他們只是感情好杀糯,可當(dāng)我...
    茶點故事閱讀 67,611評論 6 392
  • 文/花漫 我一把揭開白布扫俺。 她就那樣靜靜地躺著,像睡著了一般固翰。 火紅的嫁衣襯著肌膚如雪狼纬。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,482評論 1 302
  • 那天骂际,我揣著相機與錄音疗琉,去河邊找鬼。 笑死审磁,一個胖子當(dāng)著我的面吹牛潮饱,可吹牛的內(nèi)容都是我干的常遂。 我是一名探鬼主播,決...
    沈念sama閱讀 40,271評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼柠贤,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了类缤?” 一聲冷哼從身側(cè)響起臼勉,我...
    開封第一講書人閱讀 39,166評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎餐弱,沒想到半個月后宴霸,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體镜盯,經(jīng)...
    沈念sama閱讀 45,608評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,814評論 3 336
  • 正文 我和宋清朗相戀三年猖败,在試婚紗的時候發(fā)現(xiàn)自己被綠了速缆。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,926評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡恩闻,死狀恐怖艺糜,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情幢尚,我是刑警寧澤破停,帶...
    沈念sama閱讀 35,644評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站尉剩,受9級特大地震影響真慢,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜理茎,卻給世界環(huán)境...
    茶點故事閱讀 41,249評論 3 329
  • 文/蒙蒙 一黑界、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧皂林,春花似錦朗鸠、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,866評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至沟启,卻和暖如春忆家,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背德迹。 一陣腳步聲響...
    開封第一講書人閱讀 32,991評論 1 269
  • 我被黑心中介騙來泰國打工芽卿, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人浦辨。 一個月前我還...
    沈念sama閱讀 48,063評論 3 370
  • 正文 我出身青樓蹬竖,卻偏偏與公主長得像,于是被迫代替她去往敵國和親流酬。 傳聞我的和親對象是個殘疾皇子币厕,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,871評論 2 354

推薦閱讀更多精彩內(nèi)容