力扣
1. 完全背包:物品是wordDict中的单词,背包是s;
2. dp数组及其下标的含义:dp[i]表示长度为 i 的字符串是否可以被拆分为 wordDict 中的单词;dp[i] = 1表示可以拆分,dp[i] = 0表示不能拆分;
3. 递推公式:当j < i时,若dp[j] = 1,且 [j,i] 区间的子串出现在字典里,那么 dp[i] = 1。
4. 初始化:dp[0] = 1(dp[0]是递推起点),下标非0的 dp[i] 初始化为false,只要没被覆盖,就说明不可拆分。
5. 遍历顺序:求排列数,外层for循环遍历背包,内层for循环遍历物品。
class Solution {
public boolean wordBreak(String s, List wordDict) {
HashSet set = new HashSet<>(wordDict);
int[] dp = new int[s.length()+1];
dp[0] = 1;
for(int i=1;i<=s.length();i++){
for(int j=0;j
使用memo数组保存每次计算的以startIndex为起点的计算结果。如果memo[startIndex]已经被标记,那么直接返回memory[startIndex]的结果。
class Solution {
private Set set;
private int[] memo;
public boolean wordBreak(String s, List wordDict) {
memo = new int[s.length()];
set = new HashSet<>(wordDict);
return backTracking(s,0);
}
public boolean backTracking(String s, int startIndex){
if(startIndex==s.length()) return true;
if(memo[startIndex]==-1) return false;
for(int i=startIndex;i
多重背包理论基础
1. 问题形式:有N种物品和一个容量为V 的背包。第i种物品最多有Mi件可用,每件耗费的空间是Ci ,价值是Wi 。求将哪些物品装入背包,可使耗费的空间不超过背包容量,且价值总和最大。
2. 思路:转化为01背包问题。每件物品最多有Mi件可用,那就把Mi件摊开,每件的数量是1。
//版本一:改变物品数量为01背包格式
public void testMultiPack1(){
List weight = new ArrayList<>(Arrays.asList(1, 3, 4));
List value = new ArrayList<>(Arrays.asList(15, 20, 30));
List nums = new ArrayList<>(Arrays.asList(2, 3, 2));
int bagWeight = 10;
for (int i = 0; i < nums.size(); i++) {
while (nums.get(i) > 1) { //把物品展开为i
weight.add(weight.get(i));
value.add(value.get(i));
nums.set(i, nums.get(i) - 1);
}
}
int[] dp = new int[bagWeight + 1];
for(int i = 0; i < weight.size(); i++) { //遍历物品
for(int j = bagWeight; j >= weight.get(i); j--) { //遍历背包容量
dp[j] = Math.max(dp[j], dp[j - weight.get(i)] + value.get(i));
}
System.out.println(Arrays.toString(dp));
}
}
public void testMultiPack2(){
int[] weight = {1, 3, 4};
int[] value = {15, 20, 30};
int[] nums = {2, 3, 2};
int bagWeight = 10;
int[] dp = new int[bagWeight + 1];
for(int i = 0; i < weight.length; i++) { //遍历物品
for(int j = bagWeight; j >= weight[i]; j--) { //遍历背包容量
//遍历个数
for (int k = 1; k <= nums[i] && (j - k * weight[i]) >= 0; k++) {
dp[j] = Math.max(dp[j], dp[j - k * weight[i]] + k * value[i]);
}
System.out.println(Arrays.toString(dp));
}
}
}
背包总结篇
背包递推公式:
1. 能否装满背包(或者最多能装多少):dp[j] = max(dp[j],dp[j-nums[i]]+nums[i]);
2. 装满背包有几种方法:dp[j] += dp[j-nums[i]];
3. 装满背包,最大价值:dp[j] = max(dp[j],dp[j-nums[i]]+value[i]);
4. 装满背包的最小物品数目:dp[j] = min(dp[j-coins[i]]+1, dp[j]);
遍历顺序:
1. 01背包:
(1)二维dp数组,先遍历物品再遍历背包,或者先遍历背包再遍历物品都可以,且第二层for循环从小到大;
(2)一维dp数组,只能先遍历物品再遍历背包容量,且第二层for循环从大到小;
2. 完全背包:
(1)纯完全背包,先遍历物品或先遍历背包都可以,且第二层for循环从小到大。
(2)求组合数,外层for循环遍历物品,内层for遍历背包。
(3)求排列数,外层for遍历背包,内层for循环遍历物品。