国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

動(dòng)態(tài)規(guī)劃之背包問(wèn)題——完全背包

這篇具有很好參考價(jià)值的文章主要介紹了動(dòng)態(tài)規(guī)劃之背包問(wèn)題——完全背包。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

算法相關(guān)數(shù)據(jù)結(jié)構(gòu)總結(jié):

序號(hào) 數(shù)據(jù)結(jié)構(gòu) 文章
1 動(dòng)態(tài)規(guī)劃 動(dòng)態(tài)規(guī)劃之背包問(wèn)題——01背包
動(dòng)態(tài)規(guī)劃之背包問(wèn)題——完全背包
動(dòng)態(tài)規(guī)劃之打家劫舍系列問(wèn)題
動(dòng)態(tài)規(guī)劃之股票買賣系列問(wèn)題
動(dòng)態(tài)規(guī)劃之子序列問(wèn)題
算法(Java)——?jiǎng)討B(tài)規(guī)劃
2 數(shù)組 算法分析之?dāng)?shù)組問(wèn)題
3 鏈表 算法分析之鏈表問(wèn)題
算法(Java)——鏈表
4 二叉樹(shù) 算法分析之二叉樹(shù)
算法分析之二叉樹(shù)遍歷
算法分析之二叉樹(shù)常見(jiàn)問(wèn)題
算法(Java)——二叉樹(shù)
5 哈希表 算法分析之哈希表
算法(Java)——HashMap、HashSet、ArrayList
6 字符串 算法分析之字符串
算法(Java)——字符串String
7 棧和隊(duì)列 算法分析之棧和隊(duì)列
算法(Java)——棧、隊(duì)列、堆
8 貪心算法 算法分析之貪心算法
9 回溯 Java實(shí)現(xiàn)回溯算法入門(mén)(排列+組合+子集)
Java實(shí)現(xiàn)回溯算法進(jìn)階(搜索)
10 二分查找 算法(Java)——二分法查找
11 雙指針、滑動(dòng)窗口 算法(Java)——雙指針
算法分析之滑動(dòng)窗口類問(wèn)題

前面整理了01背包,在leetcode題庫(kù)中主要就是01背包和完全背包問(wèn)題,所以在這里整理一下完全背包的知識(shí)點(diǎn)。

一、完全背包問(wèn)題

有N件物品和一個(gè)最多能背重量為W的背包。第i件物品的重量是weight[i],得到的價(jià)值是value[i] 。每件物品都有無(wú)限個(gè)(也就是可以放入背包多次),求解將哪些物品裝入背包里物品價(jià)值總和最大。

完全背包和01背包問(wèn)題唯一不同的地方就是,每種物品有無(wú)限件。

注:leetcode上沒(méi)有純完全背包問(wèn)題,都是需要完全背包的各種應(yīng)用,需要轉(zhuǎn)化成完全背包問(wèn)題

01背包和完全背包唯一不同就是體現(xiàn)在遍歷順序上,所以針對(duì)遍歷順序進(jìn)行分析。其它動(dòng)規(guī)五部曲參考01背包。

二、完全背包遍歷順序

首先回顧一下01背包的遍歷順序:

for(int i = 0; i < weight.size(); i++) { // 遍歷物品
    for(int j = bagWeight; j >= weight[i]; j--) { // 遍歷背包容量
        dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
    }
}

我們知道01背包內(nèi)嵌的循環(huán)是從大到小遍歷,為了保證每個(gè)物品僅被添加一次。

而完全背包的物品是可以添加多次的,所以要從小到大去遍歷,即:

// 先遍歷物品,再遍歷背包
int[] dp = new int[bagWeight + 1];
for (int i = 0; i < weight.length; i++){
    for (int j = 1; j <= bagWeight; j++){
        if (j - weight[i] >= 0){
            dp[j] = Math.max(dp[j], dp[j - weight[i]] + value[i]);
        }
    }
}

為什么遍歷物品在外層循環(huán),遍歷背包容量在內(nèi)層循環(huán)?

在01背包中二維dp數(shù)組的兩個(gè)for遍歷的先后循序是可以顛倒,一維dp數(shù)組的兩個(gè)for循環(huán)先后循序一定是先遍歷物品,再遍歷背包容量。

在完全背包中,對(duì)于一維dp數(shù)組來(lái)說(shuō),其實(shí)兩個(gè)for循環(huán)嵌套順序同樣無(wú)所謂。

因?yàn)?code>dp[j] 是根據(jù) 下標(biāo)j之前所對(duì)應(yīng)的dp[j]計(jì)算出來(lái)的。 只要保證下標(biāo)j之前的dp[j]都是經(jīng)過(guò)計(jì)算的就可以。完全背包中,兩個(gè)for循環(huán)的先后循序,都不影響計(jì)算dp[j]所需要的值。

先遍歷被背包在遍歷物品,代碼如下:

// 先遍歷背包,再遍歷物品
for(int j = 0; j <= bagWeight; j++) { // 遍歷背包容量
    for(int i = 0; i < weight.size(); i++) { // 遍歷物品
        if (j - weight[i] >= 0) dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
    }
}

:全文說(shuō)的都是對(duì)于純完全背包問(wèn)題,其for循環(huán)的先后循環(huán)是可以顛倒的!但如果題目稍稍有點(diǎn)變化,就會(huì)體現(xiàn)在遍歷順序上。

如果問(wèn)裝滿背包有幾種方式的話? 那么兩個(gè)for循環(huán)的先后順序就有很大區(qū)別了,而leetcode上的題目都是這種稍有變化的類型。這些將根據(jù)具體的題目進(jìn)行分析。

三、leetcode例題講解完全背包問(wèn)題

518. 零錢兌換 II

leetcode題目鏈接:518. 零錢兌換 II

給你一個(gè)整數(shù)數(shù)組 coins 表示不同面額的硬幣,另給一個(gè)整數(shù) amount 表示總金額。

請(qǐng)你計(jì)算并返回可以湊成總金額的硬幣組合數(shù)。如果任何硬幣組合都無(wú)法湊出總金額,返回 0 。

假設(shè)每一種面額的硬幣有無(wú)限個(gè)。

示例一:

輸入:amount = 5, coins = [1, 2, 5]
輸出:4
解釋:有四種方式可以湊成總金額:
5=5
5=2+2+1
5=2+1+1+1
5=1+1+1+1+1

示例二:

輸入:amount = 3, coins = [2]
輸出:0
解釋:只用面額 2 的硬幣不能湊成總金額 3 。

示例三:

輸入:amount = 10, coins = [10] 
輸出:1

這是一道典型的背包問(wèn)題,一看到錢幣數(shù)量不限,就知道這是一個(gè)完全背包。

但本題和純完全背包不一樣,純完全背包是能否湊成總金額,而本題是要求湊成總金額的個(gè)數(shù)

然后就是組合數(shù):組合不強(qiáng)調(diào)元素之間的順序,排列強(qiáng)調(diào)元素之間的順序。

1.確定dp數(shù)組以及下標(biāo)的含義

dp[i]:湊成總金額i的貨幣組合數(shù)為dp[i]

2.確定遞推公式

dp[i] (考慮coins[j]的組合總和) 就是所有的dp[i - coins[j]](不考慮coins[j])相加。

所以遞推公式:dp[i] += dp[i - coins[j]]; 和01背包相同。

3.dp數(shù)組如何初始化

dp[0]一定要為1,dp[0] = 1是 遞歸公式的基礎(chǔ)。

從dp[i]的含義上來(lái)講就是,湊成總金額0的貨幣組合數(shù)為1。

下標(biāo)非0的dp[j]初始化為0,這樣累計(jì)加dp[i - coins[j]]的時(shí)候才不會(huì)影響真正的dp[i]

4.確定遍歷順序

本題是外層for循環(huán)遍歷物品(錢幣),內(nèi)層for遍歷背包(金錢總額),還是外層for遍歷背包(金錢總額),內(nèi)層for循環(huán)遍歷物品(錢幣)呢?

在上面講解了完全背包的兩個(gè)for循環(huán)的先后順序都是可以的。但本題就不行了。

因?yàn)?strong>純完全背包求得是能否湊成總和,和湊成總和的元素有沒(méi)有順序沒(méi)關(guān)系,即:有順序也行,沒(méi)有順序也行!

本題要求湊成總和的組合數(shù),元素之間要求沒(méi)有順序

所以純完全背包是能湊成總和就行,不用管怎么湊的。

本題是求湊出來(lái)的方案?jìng)€(gè)數(shù),且每個(gè)方案?jìng)€(gè)數(shù)是為組合數(shù)。

先來(lái)看 外層for循環(huán)遍歷物品(錢幣),內(nèi)層for遍歷背包(金錢總額)的情況。

舉例用的dp[j] += dp[j - coins[i]]; 這里就不再改了。

for (int i = 0; i < coins.size(); i++) { // 遍歷物品
    for (int j = coins[i]; j <= amount; j++) { // 遍歷背包容量
        dp[j] += dp[j - coins[i]];
    }
}

假設(shè):coins[0] = 1,coins[1] = 5。

那么就是先把1加入計(jì)算,然后再把5加入計(jì)算,得到的方法數(shù)量只有{1, 5}這種情況。而不會(huì)出現(xiàn){5, 1}的情況。

這種遍歷順序中dp[j]里計(jì)算的是組合數(shù)!

另外一種遍歷順序:

for (int j = 0; j <= amount; j++) { // 遍歷背包容量
    for (int i = 0; i < coins.size(); i++) { // 遍歷物品
        if (j - coins[i] >= 0) dp[j] += dp[j - coins[i]];
    }
}

背包容量的每一個(gè)值,都是經(jīng)過(guò) 1 和 5 的計(jì)算,包含了{(lán)1, 5} 和 {5, 1}兩種情況。

此時(shí)dp[j]里算出來(lái)的就是排列數(shù)

5.舉例推導(dǎo)dp數(shù)組

省略。

Java代碼實(shí)現(xiàn)

class Solution {
    public int change(int amount, int[] coins) {
        // 動(dòng)態(tài)規(guī)劃,dp[i]表示湊成金額i的硬幣組合數(shù)
        // dp[i] += dp[i - coins[j]]
        // dp[0] = 1
        // 遍歷順序:本題先循環(huán)錢幣,后循環(huán)金錢總額,否則就會(huì)有重復(fù){1,5}和{5,1}就成了兩種方法
        int[] dp = new int[amount+1];
        dp[0] = 1;
        for(int j = 0; j < coins.length; j++){
            for(int i = coins[j]; i <= amount; i++){
                    dp[i] += dp[i - coins[j]];
            }
        }
        return dp[amount];
    }
}
377. 組合總和 Ⅳ

leetcode題目鏈接:377. 組合總和 Ⅳ

給你一個(gè)由 不同 整數(shù)組成的數(shù)組 nums ,和一個(gè)目標(biāo)整數(shù) target 。請(qǐng)你從 nums 中找出并返回總和為 target 的元素組合的個(gè)數(shù)。

示例一:

輸入:nums = [1,2,3], target = 4
輸出:7
解釋:
所有可能的組合為:
(1, 1, 1, 1)
(1, 1, 2)
(1, 2, 1)
(1, 3)
(2, 1, 1)
(2, 2)
(3, 1)
請(qǐng)注意,順序不同的序列被視作不同的組合。

示例二:

輸入:nums = [9], target = 3
輸出:0

本題題目描述說(shuō)是求組合,但又說(shuō)是可以元素相同順序不同的組合算兩個(gè)組合,其實(shí)就是求排列!

組合不強(qiáng)調(diào)順序,(1,5)和(5,1)是同一個(gè)組合。

排列強(qiáng)調(diào)順序,(1,5)和(5,1)是兩個(gè)不同的排列。

但其本質(zhì)是本題求的是排列總和,而且僅僅是求排列總和的個(gè)數(shù),并不是把所有的排列都列出來(lái)。

1.確定dp數(shù)組以及下標(biāo)的含義

dp[i]: 湊成目標(biāo)正整數(shù)為i的排列個(gè)數(shù)為dp[i]

2.確定遞推公式

dp[i](考慮nums[j])可以由 dp[i - nums[j]](不考慮nums[j]) 推導(dǎo)出來(lái)。

因?yàn)橹灰玫絥ums[j],排列個(gè)數(shù)dp[i - nums[j]],就是dp[i]的一部分。

所以遞推公式:dp[i] += dp[i - nums[j]]; 和01背包相同。

3.dp數(shù)組如何初始化

因?yàn)檫f推公式dp[i] += dp[i - nums[j]]的緣故,dp[0]要初始化為1,這樣遞歸其他dp[i]的時(shí)候才會(huì)有數(shù)值基礎(chǔ)。

其實(shí)沒(méi)有意義,所以我也不去強(qiáng)行解釋它的意義了,因?yàn)轭}目中也說(shuō)了:給定目標(biāo)值是正整數(shù)! 所以dp[0] = 1是沒(méi)有意義的,僅僅是為了推導(dǎo)遞推公式。

至于非0下標(biāo)的dp[i]應(yīng)該初始為多少呢?

初始化為0,這樣才不會(huì)影響dp[i]累加所有的dp[i - nums[j]]。

4.確定遍歷順序

個(gè)數(shù)可以不限使用,說(shuō)明這是一個(gè)完全背包。

得到的集合是排列,說(shuō)明需要考慮元素之間的順序。

如果求排列數(shù)就是外層for遍歷背包,內(nèi)層for循環(huán)遍歷物品。

如果把遍歷nums(物品)放在外循環(huán),遍歷target的作為內(nèi)循環(huán)的話,舉一個(gè)例子:計(jì)算dp[4]的時(shí)候,結(jié)果集只有 {1,3} 這樣的集合,不會(huì)有{3,1}這樣的集合,因?yàn)閚ums遍歷放在外層,3只能出現(xiàn)在1后面!

所以本題遍歷順序最終遍歷順序:target(背包)放在外循環(huán),將nums(物品)放在內(nèi)循環(huán),內(nèi)循環(huán)從前到后遍歷。

5.舉例推導(dǎo)dp數(shù)組

省略。

Java代碼實(shí)現(xiàn)

class Solution {
    public int combinationSum4(int[] nums, int target) {
        // 動(dòng)態(tài)規(guī)劃,完全背包,dp[i] 表示返回元素總和i的元素組合個(gè)數(shù)
        // dp[i] += dp[i - nums[j]]
        // dp[0] = 1
        // 遍歷順序也需要考慮,對(duì)于每一個(gè)元素和來(lái)說(shuō),遍歷加每一個(gè)小于和的元素,先遍歷背包,再遍歷物品
        // 雖說(shuō)是組合問(wèn)題,但(1, 1, 2),(1, 2, 1),(2, 1, 1)是三種組合,所以與一般組合問(wèn)題不同
        int[] dp = new int[target+1];
        dp[0] = 1;
        for(int i = 0; i <= target; i++){  // 遍歷背包
            for(int j = 0; j < nums.length; j++){  // 遍歷物品
                if(i >= nums[j]){
                    dp[i] += dp[i - nums[j]];
                }
            }
        }
        return dp[target];
    }
}
322. 零錢兌換

leetcode題目鏈接:322. 零錢兌換
給你一個(gè)整數(shù)數(shù)組 coins ,表示不同面額的硬幣;以及一個(gè)整數(shù) amount ,表示總金額。

計(jì)算并返回可以湊成總金額所需的 最少的硬幣個(gè)數(shù) 。如果沒(méi)有任何一種硬幣組合能組成總金額,返回 -1 。

你可以認(rèn)為每種硬幣的數(shù)量是無(wú)限的。

示例一:

輸入:coins = [1, 2, 5], amount = 11
輸出:3 
解釋:11 = 5 + 5 + 1

示例二:

輸入:coins = [2], amount = 3
輸出:-1

示例三:

輸入:coins = [1], amount = 0
輸出:0

這道題還是零錢兌換,但套路不一樣。

題目中說(shuō)每種硬幣的數(shù)量是無(wú)限的,可以看出是典型的完全背包問(wèn)題。

1.確定dp數(shù)組以及下標(biāo)的含義

dp[i]:湊足總額為i所需錢幣的最少個(gè)數(shù)為dp[i]

2.確定遞推公式

得到dp[i](考慮coins[j]),只有一個(gè)來(lái)源,dp[i - coins[j]](沒(méi)有考慮coins[j])。

湊足總額為i - coins[j]的最少個(gè)數(shù)為dp[i - coins[j]],那么只需要加上一個(gè)錢幣coins[j]即dp[i - coins[j]] + 1就是dp[i](考慮coins[j])

所以dp[j] 要取所有 dp[i - coins[j]] + 1 中最小的。

遞推公式:dp[i] = min(dp[i - coins[j]] + 1, dp[i]);

3.dp數(shù)組如何初始化

首先湊足總金額為0所需錢幣的個(gè)數(shù)一定是0,那么dp[0] = 0;

其他下標(biāo)對(duì)應(yīng)的數(shù)值呢?

考慮到遞推公式的特性,dp[j]必須初始化為一個(gè)最大的數(shù),否則就會(huì)在min(dp[i - coins[j]] + 1, dp[i])比較的過(guò)程中被初始值覆蓋。

所以下標(biāo)非0的元素都是應(yīng)該是最大值。

注:計(jì)算min,初始化是最大值,計(jì)算max初始化是0。

4.確定遍歷順序

本題求錢幣最小個(gè)數(shù),那么錢幣有順序和沒(méi)有順序都可以,都不影響錢幣的最小個(gè)數(shù)。。

所以本題并不強(qiáng)調(diào)集合是組合還是排列。

所以本題的兩個(gè)for循環(huán)的關(guān)系是:外層for循環(huán)遍歷物品,內(nèi)層for遍歷背包或者外層for遍歷背包,內(nèi)層for循環(huán)遍歷物品都是可以的!

5.舉例推導(dǎo)dp數(shù)組

省略。

Java代碼實(shí)現(xiàn)

class Solution {
    // int minCount = Integer.MAX_VALUE;
    public int coinChange(int[] coins, int amount) {
        // 動(dòng)態(tài)規(guī)劃 dp[i] 表示組成金額i所需最少的硬幣數(shù)量,典型的完全背包問(wèn)題
        if(amount == 0) return 0;
        int[] dp = new int[amount+1]; 
        Arrays.fill(dp, amount+1);  // 也可以直接填充Integer.MAX_VALUE
        dp[0] = 0;
        for(int i = 1; i < amount+1; i++){  // 數(shù)量,遍歷背包
            for(int j = 0; j < coins.length; j++){  // 金額,遍歷物品
                // 最小硬幣數(shù) = 最小硬幣數(shù)與該金額減去一個(gè)面值的最小硬幣數(shù)+1
                if(coins[j] <= i){
                    dp[i] = Math.min(dp[i], dp[i - coins[j]] + 1);
                }
            }
        }
        return dp[amount] > amount ? -1 : dp[amount];
}
279. 完全平方數(shù)

leetcode題目鏈接:279.完全平方數(shù)

給定正整數(shù) n,找到若干個(gè)完全平方數(shù)(比如 1, 4, 9, 16, …)使得它們的和等于 n。你需要讓組成和的完全平方數(shù)的個(gè)數(shù)最少。

給你一個(gè)整數(shù) n ,返回和為 n 的完全平方數(shù)的 最少數(shù)量 。

完全平方數(shù) 是一個(gè)整數(shù),其值等于另一個(gè)整數(shù)的平方;換句話說(shuō),其值等于一個(gè)整數(shù)自乘的積。例如,1、4、9 和 16 都是完全平方數(shù),而 3 和 11 不是。

示例一:

輸入:n = 12
輸出:3 
解釋:12 = 4 + 4 + 4

示例二:

輸入:n = 13
輸出:2
解釋:13 = 4 + 9

把題目翻譯一下:完全平方數(shù)就是物品(可以無(wú)限件使用),湊個(gè)正整數(shù)n就是背包,問(wèn)湊滿這個(gè)背包最少有多少物品?

這樣就回到了熟悉的完全背包問(wèn)題。

1.確定dp數(shù)組以及下標(biāo)的含義

dp[i]:和為i的完全平方數(shù)的最少數(shù)量為dp[i]

2.確定遞推公式

dp[i] 可以由dp[i - j * j]推出, dp[i - j * j] + 1 便可以湊成dp[j]。

此時(shí)我們要選擇最小的dp[j],所以遞推公式:dp[i] = min(dp[i - j * j] + 1, dp[i]);

3.dp數(shù)組如何初始化

dp[0]表示 和為0的完全平方數(shù)的最小數(shù)量,那么dp[0]一定是0。

題目描述,找到若干個(gè)完全平方數(shù)(比如 1, 4, 9, 16, …),題目描述中可沒(méi)說(shuō)要從0開(kāi)始,dp[0]=0完全是為了遞推公式。

非0下標(biāo)的dp[i]應(yīng)該是多少呢?

從遞歸公式dp[i] = min(dp[i - j * j] + 1, dp[i]);中可以看出每次dp[j]都要選最小的,所以非0下標(biāo)的dp[i]一定要初始為最大值,這樣dp[i]在遞推的時(shí)候才不會(huì)被初始值覆蓋。

4.確定遍歷順序

本題的兩個(gè)for循環(huán)的關(guān)系是:外層for循環(huán)遍歷物品,內(nèi)層for遍歷背包或者外層for遍歷背包,內(nèi)層for循環(huán)遍歷物品都是可以的!

5.舉例推導(dǎo)dp數(shù)組

省略。

Java代碼實(shí)現(xiàn)

class Solution {
    public int numSquares(int n) {
        // 動(dòng)態(tài)規(guī)劃,完全背包
        // dp[i] 表示和為i的完全平方數(shù)的最小數(shù)量
        int[] dp = new int[n+1];
        Arrays.fill(dp, Integer.MAX_VALUE);
        dp[0] = 0;
        for(int i = 1; i <= n; i++){  // 先背包
            for(int j = 1; j * j <= i; j++){  // 再物品
                dp[i] = Math.min(dp[i], dp[i - j * j] + 1);
            }
        }
        return dp[n];
    }
}
139. 單詞拆分

leetcode題目鏈接:139. 單詞拆分

給你一個(gè)字符串 s 和一個(gè)字符串列表 wordDict 作為字典,判定 s 是否可以由空格拆分為一個(gè)或多個(gè)在字典中出現(xiàn)的單詞。

說(shuō)明:拆分時(shí)可以重復(fù)使用字典中的單詞。

示例一:

輸入: s = "leetcode", wordDict = ["leet", "code"]
輸出: true
解釋: 返回 true 因?yàn)?"leetcode" 可以被拆分成 "leet code"。

示例二:

輸入: s = "applepenapple", wordDict = ["apple", "pen"]
輸出: true
解釋: 返回 true 因?yàn)?"applepenapple" 可以被拆分成 "apple pen apple"。
     注意你可以重復(fù)使用字典中的單詞。

示例三:

輸入: s = "catsandog", wordDict = ["cats", "dog", "sand", "and", "cat"]
輸出: false

單詞就是物品,字符串s就是背包,單詞能否組成字符串s,就是問(wèn)物品能不能把背包裝滿。

拆分時(shí)可以重復(fù)使用字典中的單詞,說(shuō)明就是一個(gè)完全背包!

1.確定dp數(shù)組以及下標(biāo)的含義

dp[i] : 字符串長(zhǎng)度為i的話,dp[i]為true,表示可以拆分為一個(gè)或多個(gè)在字典中出現(xiàn)的單詞。

2.確定遞推公式

如果確定dp[j] 是true,且 [j, i] 這個(gè)區(qū)間的子串出現(xiàn)在字典里,那么dp[i]一定是true。(j < i )。

所以遞推公式是 if([j, i] 這個(gè)區(qū)間的子串出現(xiàn)在字典里 && dp[j]是true) 那么 dp[i] = true。

3.dp數(shù)組如何初始化

從遞歸公式中可以看出,dp[i] 的狀態(tài)依靠 dp[j]是否為true,那么dp[0]就是遞歸的根基,dp[0]一定要為true,否則遞歸下去后面都都是false了。

下標(biāo)非0的dp[i]初始化為false,只要沒(méi)有被覆蓋說(shuō)明都是不可拆分為一個(gè)或多個(gè)在字典中出現(xiàn)的單詞。

4.確定遍歷順序

本題最終要求的是是否都出現(xiàn)過(guò),所以對(duì)出現(xiàn)單詞集合里的元素是組合還是排列,并不在意!

所以本題的兩個(gè)for循環(huán)的關(guān)系是:外層for循環(huán)遍歷物品,內(nèi)層for遍歷背包或者外層for遍歷背包,內(nèi)層for循環(huán)遍歷物品都是可以的!

5.舉例推導(dǎo)dp數(shù)組

省略。

Java代碼實(shí)現(xiàn):

class Solution {
    public boolean wordBreak(String s, List<String> wordDict) {
        // 動(dòng)態(tài)規(guī)劃
        // dp[i] 表示以i-1結(jié)尾的字符串能否拆分成字典中得單詞
        boolean[] dp = new boolean[s.length()+1];
        dp[0] = true;
        for(int i = 1; i <= s.length(); i++){
            for(int j = 0; j < i; j++){
                if(dp[j] && wordDict.contains(s.substring(j, i))){
                    dp[i] = true;
                }
            }
        }
        return dp[s.length()];
    }
}

簡(jiǎn)單的優(yōu)化,當(dāng)dp[i]=true,可以break,減少遍歷的次數(shù)。

for(int i = 1; i <= s.length(); i++){
    for(int j = 0; j < i; j++){
        if(dp[j] && wordDict.contains(s.substring(j, i))){
            dp[i] = true;
            break;
        }
    }
}

四、完全背包問(wèn)題總結(jié)

1. 動(dòng)規(guī)五步分析法
  1. 確定dp數(shù)組(dp table)以及下標(biāo)的含義
  2. 確定遞推公式
  3. dp數(shù)組如何初始化
  4. 確定遍歷順序
  5. 舉例推導(dǎo)dp數(shù)組
2. 背包遞推公式

問(wèn)裝滿背包有幾種方法:dp[i] += dp[i - nums[j]] ,對(duì)應(yīng)題目如下:

518. 零錢兌換 II

377. 組合總和 Ⅳ

問(wèn)裝滿背包所有物品的最小個(gè)數(shù):dp[i] = min(dp[i - coins[j]] + 1, dp[i]); ,對(duì)應(yīng)題目如下:

322. 零錢兌換

279.完全平方數(shù)

3. 遍歷順序

純完全背包的一維dp數(shù)組實(shí)現(xiàn),先遍歷物品還是先遍歷背包都是可以的,且第二層for循環(huán)是從小到大遍歷。

如果求組合數(shù)就是外層for循環(huán)遍歷物品,內(nèi)層for遍歷背包。

求組合數(shù):518. 零錢兌換 II

如果求排列數(shù)就是外層for遍歷背包,內(nèi)層for循環(huán)遍歷物品。

求排列數(shù):377. 組合總和 Ⅳ

如果求最小數(shù),那么兩層for循環(huán)的先后順序就無(wú)所謂了。

求最小數(shù):322. 零錢兌換、279.完全平方數(shù)

對(duì)于背包問(wèn)題,其實(shí)遞推公式算是容易的,難是難在遍歷順序上。

參考:完全背包理論基礎(chǔ)文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-435693.html

到了這里,關(guān)于動(dòng)態(tài)規(guī)劃之背包問(wèn)題——完全背包的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 力扣算法刷題Day44|動(dòng)態(tài)規(guī)劃:完全背包問(wèn)題 零錢兌換II 組合總和Ⅳ

    力扣題目:#518.零錢兌換II(完全背包組合問(wèn)題) 刷題時(shí)長(zhǎng):7min 解題方法:動(dòng)態(tài)規(guī)劃(完全背包) 復(fù)雜度分析 時(shí)間復(fù)雜度: O(mn),其中 m 是amount,n 是 coins 的長(zhǎng)度 空間復(fù)雜度: O(m) 問(wèn)題總結(jié) 對(duì)遞推公式的理解 本題收獲 題意轉(zhuǎn)換:純完全背包是湊成背包最大價(jià)值是多少,而本

    2024年02月13日
    瀏覽(27)
  • 動(dòng)態(tài)規(guī)劃-背包問(wèn)題-完全背包

    對(duì)比01背包,完全背包中的每件物品有無(wú)數(shù)件。 也就是說(shuō),每件物品可以拿0,1,…,k,…件。 dp[i][j]表示前i種物品,體積為j時(shí)的最大價(jià)值 對(duì)于第i件物品: 不拿:dp[i][j]?dp[i-1][j] 拿一件:dp[i][j]?dp[i-1][j-w[i]]+v[i] 拿兩件:dp[i][j]?dp[i-1][j-2w[i]]+2v[i] … 拿k件:dp[i]][j]?dp[i

    2024年04月08日
    瀏覽(20)
  • 完全背包&多重背包問(wèn)題(動(dòng)態(tài)規(guī)劃)

    完全背包問(wèn)題: 每個(gè)物品使用次數(shù)沒(méi)有限制,與0-1背包的不同之處在于 遍歷背包的順序 是正序。 多重背包問(wèn)題: 與完全背包的區(qū)別在于,每一種物品是有個(gè)數(shù)限制的,不能無(wú)限選擇。這篇博客講解的非常詳細(xì),可以參考學(xué)習(xí): 多重背包問(wèn)題---超詳細(xì)講解+優(yōu)化(不懂你揍我

    2024年04月10日
    瀏覽(24)
  • 動(dòng)態(tài)規(guī)劃之背包問(wèn)題——完全背包

    算法相關(guān)數(shù)據(jù)結(jié)構(gòu)總結(jié): 序號(hào) 數(shù)據(jù)結(jié)構(gòu) 文章 1 動(dòng)態(tài)規(guī)劃 動(dòng)態(tài)規(guī)劃之背包問(wèn)題——01背包 動(dòng)態(tài)規(guī)劃之背包問(wèn)題——完全背包 動(dòng)態(tài)規(guī)劃之打家劫舍系列問(wèn)題 動(dòng)態(tài)規(guī)劃之股票買賣系列問(wèn)題 動(dòng)態(tài)規(guī)劃之子序列問(wèn)題 算法(Java)——?jiǎng)討B(tài)規(guī)劃 2 數(shù)組 算法分析之?dāng)?shù)組問(wèn)題 3 鏈表 算法

    2024年02月03日
    瀏覽(25)
  • 算法競(jìng)賽必考算法——?jiǎng)討B(tài)規(guī)劃(01背包和完全背包)

    算法競(jìng)賽必考算法——?jiǎng)討B(tài)規(guī)劃(01背包和完全背包)

    1.1題目介紹 1.2思路一介紹(二維數(shù)組) 代碼如下: 1.3思路二介紹(一維數(shù)組) 空間優(yōu)化 ??為什么可以使用一維數(shù)組? ??我們先來(lái)看一看01背包問(wèn)題的狀態(tài)轉(zhuǎn)移方程,我們可以發(fā)現(xiàn) f[i]只用到了f[i-1],其他的是沒(méi)有用到的,我們可以用滾動(dòng)數(shù)組來(lái)做。 ??還有一個(gè)原因就是我

    2024年02月02日
    瀏覽(20)
  • 【動(dòng)態(tài)規(guī)劃之完全背包問(wèn)題】完全背包問(wèn)題的通用解法與優(yōu)化

    【動(dòng)態(tài)規(guī)劃之完全背包問(wèn)題】完全背包問(wèn)題的通用解法與優(yōu)化

    ?? 前面的話 ?? 本篇文章將介紹動(dòng)態(tài)規(guī)劃中的背包問(wèn)題——完全背包問(wèn)題,前面我們已經(jīng)介紹了0-1背包問(wèn)題,其實(shí)完全背包問(wèn)題就只改了0-1背包問(wèn)題的一個(gè)條件,即物品可選擇次數(shù)由一次改為無(wú)數(shù)次,僅此而已,下面我們就來(lái)開(kāi)始介紹完全背包問(wèn)題。 ??博客主頁(yè):未見(jiàn)

    2023年04月22日
    瀏覽(114)
  • 動(dòng)態(tài)規(guī)劃——完全背包問(wèn)題

    動(dòng)態(tài)規(guī)劃——完全背包問(wèn)題

    由于本人實(shí)力尚淺,接觸算法沒(méi)多久,寫(xiě)這篇blog僅僅是想要提升自己對(duì)算法的理解,如果各位讀者發(fā)現(xiàn)什么錯(cuò)誤,懇請(qǐng)指正,希望和大家一起進(jìn)步。(●’?’●) 了解完全背包問(wèn)題前可以先去看看01背包問(wèn)題(良心正解),先了解這個(gè)基礎(chǔ)問(wèn)題會(huì)更有利于你了解下面的完全背

    2024年02月04日
    瀏覽(29)
  • 動(dòng)態(tài)規(guī)劃:完全背包問(wèn)題

    動(dòng)態(tài)規(guī)劃:完全背包問(wèn)題

    ACwing #3. 完全背包問(wèn)題 完全背包問(wèn)題和01背包問(wèn)題很相似。 01背包問(wèn)題每個(gè)物品只能選一個(gè),而完全背包問(wèn)題每個(gè)物品可以選無(wú)限次。 DP問(wèn)題的關(guān)鍵是找到狀態(tài)轉(zhuǎn)移方程: ①定義f[i][j]表示從前 i 個(gè)物品中選擇,體積為 j 的時(shí)候的最大價(jià)值。 ②那么轉(zhuǎn)移方程f[i][j] = max(f[i - 1][j

    2023年04月19日
    瀏覽(25)
  • 動(dòng)態(tài)規(guī)劃完全背包問(wèn)題-java

    動(dòng)態(tài)規(guī)劃完全背包問(wèn)題-java

    完全背包問(wèn)題跟01背包問(wèn)題思路大致一樣,只不過(guò)對(duì)于物品的拿取次數(shù)不在限制,我們只需要考慮這點(diǎn)即可。 文章目錄 前言 一、什么是完全背包問(wèn)題? 二、問(wèn)題模擬 1.樣例數(shù)據(jù) 2.算法思路 三、代碼如下 1.代碼如下(示例): 2.讀入數(shù) 3.代碼運(yùn)行結(jié)果 總結(jié) 完全背包問(wèn)題跟

    2024年04月26日
    瀏覽(24)
  • 動(dòng)態(tài)規(guī)劃-----背包類問(wèn)題(0-1背包與完全背包)詳解

    動(dòng)態(tài)規(guī)劃-----背包類問(wèn)題(0-1背包與完全背包)詳解

    目錄 什么是背包問(wèn)題? 動(dòng)態(tài)規(guī)劃問(wèn)題的一般解決辦法: 0-1背包問(wèn)題: 0 - 1背包類問(wèn)題? 分割等和子集:? 完全背包問(wèn)題:? 完全背包類問(wèn)題 零錢兌換II: 背包問(wèn)題(Knapsack problem)是一種組合優(yōu)化的NP完全問(wèn)題。 問(wèn)題可以描述為:給定一組物品,每種物品都有自己的重量和價(jià)格

    2024年04月17日
    瀏覽(29)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包