322. 零錢兌換
如果求組合數就是外層for循環遍歷物品,內層for遍歷背包。
如果求排列數就是外層for遍歷背包,內層for循環遍歷物品。
錢幣有順序和沒有順序都可以,都不影響錢幣的最小個數。
視頻講解:動態規劃之完全背包,裝滿背包最少的物品件數是多少?| LeetCode:322.零錢兌換_嗶哩嗶哩_bilibili
代碼隨想錄
class Solution {public int coinChange(int[] coins, int amount) {if(amount == 0)return 0;int bagSize = amount;int[] dp = new int[amount + 1];Arrays.fill(dp,Integer.MAX_VALUE);//后面要取最小值,初始值都要設成最大dp[0] = 0;for(int i = 0;i <= bagSize;i++){for(int j = 0;j < coins.length;j++){if(i >= coins[j] && dp[i - coins[j]] != Integer.MAX_VALUE){dp[i] = Math.min(dp[i],dp[i - coins[j]] + 1);//初始值加一會越界}}}if(dp[amount] == Integer.MAX_VALUE)return -1;return dp[amount];}
}
279.完全平方數
279. 完全平方數 - 力扣(LeetCode)
視頻講解:動態規劃之完全背包,換湯不換藥!| LeetCode:279.完全平方數_嗶哩嗶哩_bilibili
代碼隨想錄
class Solution {public int numSquares(int n) {int[] dp = new int[n + 1];Arrays.fill(dp,Integer.MAX_VALUE);dp[0] = 0;dp[1] = 1;for(int i = 1;i*i <= n;i++){int s = i * i;for(int j = s;j <= n;j++){if(dp[j - s] != Integer.MAX_VALUE){dp[j] = Math.min(dp[j],dp[j - s] + 1);}}}return dp[n];}
}
139.單詞拆分
視頻講解:動態規劃之完全背包,你的背包如何裝滿?| LeetCode:139.單詞拆分_嗶哩嗶哩_bilibili
代碼隨想錄
dp[i]代表,數組元素是否能夠組成長度為i時的s
完全背包,正序遍歷
對順序有要求,先背包再物品
遞推公式:若前面的字符串可以被組合出來,同時后面的字符串也在數組元素里
int len = word.length();
? ? ? ? ? ? ? ? if(i >= len && dp[i - len] && set.contains(s.substring(i - len,i))){
? ? ? ? ? ? ? ? ? ? dp[i] = true;
? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? }
初始化:dp[0] = true;
class Solution {public boolean wordBreak(String s, List<String> wordDict) {Set<String> set = new HashSet<>(wordDict);boolean[] dp = new boolean[s.length() + 1];dp[0] = true;for(int i = 1;i < s.length() + 1;i++){for(String word:set){int len = word.length();if(i >= len && dp[i - len] && set.contains(s.substring(i - len,i))){dp[i] = true;break;}}}return dp[s.length()];}
}
關于多重背包,你該了解這些!
56. 攜帶礦石資源(第八期模擬筆試)
代碼隨想錄
轉化為01背包
import java.util.*;
public class Main{public static void main(String[] args){Scanner sc = new Scanner(System.in);int bagSize,n;bagSize = sc.nextInt();n = sc.nextInt();int[] weight = new int[n];int[] value = new int[n];int[] nums = new int[n];for(int i = 0;i < n;i++)weight[i] = sc.nextInt();for(int i = 0;i < n;i++)value[i] = sc.nextInt();for(int i = 0;i < n;i++)nums[i] = sc.nextInt();int[] dp = new int[bagSize + 1];for(int i = 0;i < n;i++){for(int j = bagSize;j >= weight[i];j--){for(int k = 1;k <= nums[i];k++){if(j >= k * weight[i])dp[j] = Math.max(dp[j],dp[j - k * weight[i]]+ k * value[i]);}}} System.out.println(dp[bagSize]);}
}
背包問題總結
代碼隨想錄
五部曲:
- 確定dp數組(dp table)以及下標的含義
- 確定遞推公式
- dp數組如何初始化
- 確定遍歷順序
- 舉例推導dp數組
背包遞推公式
問能否能裝滿背包(或者最多裝多少):dp[j] = max(dp[j], dp[j - nums[i]] + nums[i]);?
問裝滿背包有幾種方法:dp[j] += dp[j - nums[i]]?
問背包裝滿最大價值:dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);?
問裝滿背包所有物品的最小個數:dp[j] = min(dp[j - coins[i]] + 1, dp[j]);?
遍歷順序
01背包
二維dp數組01背包先遍歷物品還是先遍歷背包都是可以的,且第二層for循環是從小到大遍歷。
一維dp數組01背包只能先遍歷物品再遍歷背包容量,且第二層for循環是從大到小遍歷。
完全背包
純完全背包的一維dp數組實現,先遍歷物品還是先遍歷背包都是可以的,且第二層for循環是從小到大遍歷。
但是僅僅是純完全背包的遍歷順序是這樣的,題目稍有變化,兩個for循環的先后順序就不一樣了。
如果求組合數就是外層for循環遍歷物品,內層for遍歷背包。
如果求排列數就是外層for遍歷背包,內層for循環遍歷物品。
如果求最小數,那么兩層for循環的先后順序就無所謂了