[leetcode刷題筆記](méi)動(dòng)態(tài)規(guī)劃之背包問(wèn)題

當(dāng)然拿到問(wèn)題后,需要做到以下幾個(gè)步驟:
1.分析是否為背包問(wèn)題玛迄。
2.是三種背包問(wèn)題中的哪一種卵沉。
3.是0-1背包問(wèn)題還是完全背包問(wèn)題。也就是題目給的nums數(shù)組中的元素是否可以重復(fù)使用乒疏。
4.如果是組合問(wèn)題额衙,是否需要考慮元素之間的順序。需要考慮順序有順序的解法怕吴,不需要考慮順序又有對(duì)應(yīng)的解法窍侧。

三種背包問(wèn)題

組合問(wèn)題公式

dp[i] += dp[i-num]

True、False問(wèn)題公式

dp[i] = dp[i] or dp[i-num]

最大最小問(wèn)題公式

dp[i] = min(dp[i], dp[i-num]+1)或者dp[i] = max(dp[i], dp[i-num]+1)

以上三組公式是解決對(duì)應(yīng)問(wèn)題的核心公式转绷。

背包問(wèn)題的判定

背包問(wèn)題具備的特征:給定一個(gè)target伟件,target可以是數(shù)字也可以是字符串,再給定一個(gè)數(shù)組nums议经,nums中裝的可能是數(shù)字斧账,也可能是字符串,問(wèn):能否使用nums中的元素做各種排列組合得到target煞肾。

背包問(wèn)題技巧:
1.如果是0-1背包咧织,即數(shù)組中的元素不可重復(fù)使用,nums放在外循環(huán)籍救,target在內(nèi)循環(huán)习绢,且內(nèi)循環(huán)倒序;

for num in nums:
    for i in range(target, nums-1, -1):

2.如果是完全背包蝙昙,即數(shù)組中的元素可重復(fù)使用闪萄,nums放在外循環(huán),target在內(nèi)循環(huán)耸黑。且內(nèi)循環(huán)正序桃煎。

for num in nums:
    for i in range(nums, target+1):

3.如果組合問(wèn)題需考慮元素之間的順序,需將target放在外循環(huán)大刊,將nums放在內(nèi)循環(huán)为迈。

for i in range(1, target+1):
    for num in nums:

以上內(nèi)容來(lái)自希望用一種規(guī)律搞定背包問(wèn)題---Jackie1995三椿,下面介紹一些例題。

0-1背包問(wèn)題

給定n種物品和一個(gè)背包葫辐,物品i的重量是W_i,其價(jià)值為V_i,背包的容量為c搜锰。問(wèn)應(yīng)該如何選擇裝入背包的物品使得裝入背包中的物品總價(jià)值最大?

在選擇裝入背包的物品時(shí)耿战,對(duì)每種物品i只有兩種選擇蛋叼,即裝入背包或者不裝入背包。不能將物品i裝入背包多次剂陡,也不能只裝入部分的物品i狈涮。

[分析]dp [i, v]表示前i 件物品恰放入一個(gè)容量為v的背包可以獲得
的最大價(jià)值。
(1)當(dāng)C=0時(shí)鸭栖,dp[0]=0
(2)當(dāng)C>0時(shí)歌馍,每個(gè)物品都有0-1兩種狀態(tài),則其狀態(tài)轉(zhuǎn)移方程便是:

dp [i, v] = \max\{dp [i ? 1, v], dp [i ? 1, v ? C_i ] + W_i \}

[湊硬幣問(wèn)題]

有1元晕鹊,2元松却,5元硬幣若干,湊到20元最少需要多少枚硬幣溅话。

(1)n=0時(shí)晓锻,需要0個(gè)硬幣,dp[0]=0
(2)n>0時(shí)飞几,考慮最后一次硬幣硬幣情況砚哆,向前分析,即可得狀態(tài)轉(zhuǎn)移方程:

\operatorname{dp}[n]=\min \{1+d p[n-1], 1+d p[n-2], 1+d p[n-5]\}

def detectMinCoins(M,coins):
    dp = [0]*(M+1)
    for N in range(1,M+1):
        l = []
        for i in coins:
            if N>=i:
                l.append(dp[N-i]+1)
        dp[N] = min(l)
    return dp[M]

硬幣問(wèn)題

給定數(shù)量不限的硬幣循狰,幣值為25分窟社、10分、5分和1分绪钥,編寫(xiě)代碼計(jì)算n分有幾種表示法。(結(jié)果可能會(huì)很大关炼,你需要將結(jié)果模上1000000007)

[分析]
dp[i][j] 使用前i種硬幣計(jì)算j分的表示法種數(shù) 令coins=[25, 10, 5, 1]

dp[i][j] = dp[i-1][j] + dp[i-1][j-coins[i]] + dp[i-1][j-2*coins[i]] + ... dp[i-1][j-k*coins[i]]
j >= k*coins[i]
dp[i][j-coins[i]] = dp[i-1][j-coins[i]] + dp[i-1][j-2*coins[i]] + ... dp[i-1][j-k*coins[i]]
dp[i][j] - dp[i][j-coins[i]] = dp[i-1][j]
dp[i][j] = dp[i][j-coins[i]] + dp[i-1][j]

舉個(gè)例子程腹,當(dāng)n=10時(shí)

coin\n 0 1 2 3 4 5 6 7 8 9 10
0 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1 1
5 1 1 1 1 1 2 2 2 2 2 3
10 1 1 1 1 1 2 2 2 2 2 4
25 1 1 1 1 1 2 2 2 2 2 4

簡(jiǎn)化問(wèn)題,只需要得出最后一行即可儒拂。

def detectMinCoins(M,coins):
    coins = [1, 5, 10, 25]
    dp = [0] * (M + 1) 
    dp[0] = 1
    for coin in coins :
        for i in range(coin, M + 1) :
            dp[i] = (dp[i] + dp[i - coin])
    return dp[M]

打家劫舍問(wèn)題

你是一個(gè)專業(yè)的小偷寸潦,計(jì)劃偷竊沿街的房屋。每間房?jī)?nèi)都藏有一定的現(xiàn)金社痛,影響你偷竊的唯一制約因素就是相鄰的房屋裝有相互連通的防盜系統(tǒng)见转,如果兩間相鄰的房屋在同一晚上被小偷闖入,系統(tǒng)會(huì)自動(dòng)報(bào)警蒜哀。
給定一個(gè)代表每個(gè)房屋存放金額的非負(fù)整數(shù)數(shù)組斩箫,計(jì)算你 不觸動(dòng)警報(bào)裝置的情況下 ,一夜之內(nèi)能夠偷竊到的最高金額。

[分析]狀態(tài)轉(zhuǎn)移方程
數(shù)組個(gè)數(shù)length乘客,當(dāng)length=0時(shí)狐血,返回0
當(dāng)length=1時(shí),dp[0]=nums[0]
當(dāng)length=2時(shí)易核,dp[1]=max(nums[0],nums[1])
當(dāng)length=3時(shí)匈织,dp[i]=max(dp[i-2]+nums[i],dp[i-1])

class Solution:
    def rob(self, nums: List[int]) -> int:
        length = len(nums)
        if length == 0:
            return 0
        dp = [0]*length
        dp[0]=nums[0]
        if length > 1:
            dp[1] = max(nums[0],nums[1])
        if length > 2:
            for i in range(2,length):
                dp[i] = max(dp[i-2]+nums[i],dp[i-1])
        return dp[-1]

目標(biāo)和

給定一個(gè)非負(fù)整數(shù)數(shù)組,a1, a2, ..., an, 和一個(gè)目標(biāo)數(shù)牡直,S∽贺埃現(xiàn)在你有兩個(gè)符號(hào) + 和 -。對(duì)于數(shù)組中的任意一個(gè)整數(shù)碰逸,你都可以從 + 或 -中選擇一個(gè)符號(hào)添加在前面乡小。

返回可以使最終數(shù)組和為目標(biāo)數(shù) S 的所有添加符號(hào)的方法數(shù)。

示例:

輸入:nums: [1, 1, 1, 1, 1], S: 3
輸出:5
解釋:

-1+1+1+1+1 = 3
+1-1+1+1+1 = 3
+1+1-1+1+1 = 3
+1+1+1-1+1 = 3
+1+1+1+1-1 = 3

一共有5種方法讓最終目標(biāo)和為3花竞。

sum(P) 前面符號(hào)為+的集合劲件;sum(N) 前面符號(hào)為減號(hào)的集合,所以題目可以轉(zhuǎn)化為

sum(P) - sum(N) = target \\ sum(nums) + sum(P) - sum(N) = target + sum(nums)\\ 2 * sum(P) = target + sum(nums) \\ sum(P) = (target + sum(nums)) / 2

因此題目轉(zhuǎn)化為01背包约急,也就是能組合成容量為sum(P)的方式有多少種

class Solution(object):
    def findTargetSumWays(self, nums, S):
        """
        :type nums: List[int]
        :type S: int
        :rtype: int
        """
        w = (sum(nums) + S) // 2

        if sum(nums) < S or (sum(nums) + S) % 2 == 1:
            return 0

        dp = [0] * (w+1)
        dp[0] = 1
        for num in nums:
            j = w 
            while j >= num:
                dp[j] += dp[j - num]
                j -= 1
    
        return dp[w]

組合總和 Ⅳ

給定一個(gè)由正整數(shù)組成且不存在重復(fù)數(shù)字的數(shù)組零远,找出和為給定目標(biāo)正整數(shù)的組合的個(gè)數(shù)。

示例:

nums = [1, 2, 3]
target = 4

所有可能的組合為:
(1, 1, 1, 1)
(1, 1, 2)
(1, 2, 1)
(1, 3)
(2, 1, 1)
(2, 2)
(3, 1)

請(qǐng)注意厌蔽,順序不同的序列被視作不同的組合牵辣。

因此輸出為 7。

排列組合問(wèn)題首先想到貪心問(wèn)題奴饮,但這道題是明顯的動(dòng)態(tài)規(guī)劃問(wèn)題纬向,類似于上文中硬幣問(wèn)題。但與硬幣不同的是戴卜,順序不同的序列被視作不同的組合逾条。

class Solution:
    def combinationSum4(self, nums: List[int], target: int) -> int:
            dp = [0] * (target + 1) 
            dp[0] = 1
            for i in range(target + 1) :
                for num in nums :
                   if i >= num:
                        dp[i] += dp[i - num]
            return dp[-1]

更多內(nèi)容,陸續(xù)補(bǔ)充

reference

希望用一種規(guī)律搞定背包問(wèn)題---Jackie1995

題目來(lái)源:力扣LeetCode,著作權(quán)歸領(lǐng)扣網(wǎng)絡(luò)所有投剥。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末师脂,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子江锨,更是在濱河造成了極大的恐慌吃警,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,265評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件啄育,死亡現(xiàn)場(chǎng)離奇詭異酌心,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)挑豌,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門(mén)安券,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)墩崩,“玉大人,你說(shuō)我怎么就攤上這事完疫√┘Γ” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,852評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵壳鹤,是天一觀的道長(zhǎng)盛龄。 經(jīng)常有香客問(wèn)我,道長(zhǎng)芳誓,這世上最難降的妖魔是什么余舶? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,408評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮锹淌,結(jié)果婚禮上匿值,老公的妹妹穿的比我還像新娘。我一直安慰自己赂摆,他們只是感情好挟憔,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,445評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著烟号,像睡著了一般绊谭。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上汪拥,一...
    開(kāi)封第一講書(shū)人閱讀 49,772評(píng)論 1 290
  • 那天达传,我揣著相機(jī)與錄音,去河邊找鬼迫筑。 笑死宪赶,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的脯燃。 我是一名探鬼主播搂妻,決...
    沈念sama閱讀 38,921評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼辕棚!你這毒婦竟也來(lái)了叽讳?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,688評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤坟募,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后邑狸,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體懈糯,經(jīng)...
    沈念sama閱讀 44,130評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,467評(píng)論 2 325
  • 正文 我和宋清朗相戀三年单雾,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了赚哗。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片她紫。...
    茶點(diǎn)故事閱讀 38,617評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖屿储,靈堂內(nèi)的尸體忽然破棺而出贿讹,到底是詐尸還是另有隱情,我是刑警寧澤够掠,帶...
    沈念sama閱讀 34,276評(píng)論 4 329
  • 正文 年R本政府宣布民褂,位于F島的核電站,受9級(jí)特大地震影響疯潭,放射性物質(zhì)發(fā)生泄漏赊堪。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,882評(píng)論 3 312
  • 文/蒙蒙 一竖哩、第九天 我趴在偏房一處隱蔽的房頂上張望哭廉。 院中可真熱鬧,春花似錦相叁、人聲如沸遵绰。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,740評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)椿访。三九已至,卻和暖如春埠通,著一層夾襖步出監(jiān)牢的瞬間赎离,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,967評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工端辱, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留梁剔,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,315評(píng)論 2 360
  • 正文 我出身青樓舞蔽,卻偏偏與公主長(zhǎng)得像荣病,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子渗柿,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,486評(píng)論 2 348