本文主要是介绍【力扣一刷】代码随想录day44(动态规划part6 - 背包问题专题: 完全背包理论基础、卡码网52、518. 零钱兑换 II、377. 组合总和 Ⅳ ),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
【完全背包理论基础】
与01背包问题的区别:
1、物品的可取次数:完全背包和01背包问题唯一不同的地方就是,01背包问题的每种物品只能取0次或1次,而完全背包问题的每种物品可以取无限次。
2、遍历滚动数组的顺序:01背包问题每件物品最多取一次,前面取了后面就不能取,所以要逆向遍历书包容量。而完全背包问题可以取无限次,因此是正向遍历,即使前面的书包容量放过物品 i 也可以。遍历第 i 个物品,书包容量为 j 时,不取第 i 个物品,则直接返回旧值dp[ j ],取第 i 个物品时,最大容量为 dp[j - weights[i]] + values[i],其中dp[j - weights[i]]的意思是留足够的空间给需要取的第 i 个物品,再从 0 ~ i 个(包括第 i 个)物品中取,背包容量为j - weights[i]能装下的最大容量。
【52. 携带研究材料(第七期模拟笔试)】
区别:遍历书包容量的时候,是正向遍历。
import java.util.*;public class Main{public static void main (String[] args) {Scanner sc = new Scanner(System.in);int N = sc.nextInt();int V = sc.nextInt();int[] weights = new int[N];int[] values = new int[N];for (int i = 0; i < N; i++){weights[i] = sc.nextInt();values[i] = sc.nextInt();}int[] dp = new int[V+1];for (int i = 0; i < N; i++){for (int j = weights[i]; j < V + 1; j++){dp[j] = Math.max(dp[j], dp[j - weights[i]] + values[i]);}}System.out.println(dp[V]);}
}
- 时间复杂度:O(N×V),N是物品的种类数,V是容量的大小
- 空间复杂度:O(V)
【518. 零钱兑换 II】中等题
难点:
1、属于完全背包问题,需要正序遍历背包容量,从刚好能装第i个物品的背包容量开始遍历,即初始值 j = coins[i]。
2、要求的是恰好把背包装满的方案数,是放与不放的方案数的叠加,即dp[j] += dp[j - coins[i]];。
3、求的是组合数,外层for遍历的是物品,内层for遍历的是背包容量。
class Solution {public int change(int amount, int[] coins) {int dp[] = new int[amount + 1];dp[0] = 1; // 与题意理解不一样,但是设置amount=0,无论coins输入什么,输出都是1for (int i = 0; i < coins.length; i++){for (int j = coins[i]; j < amount + 1; j++){ // 完全背包:正序遍历dp[j] += dp[j - coins[i]]; // 求的是恰好装满背包的方案数,放和不放的叠加}}return dp[amount];}
}
- 时间复杂度:O(M×N),M是硬币的种类数,N是amount的数值大小
- 空间复杂度:O(N)
【377. 组合总和 Ⅳ】中等题
技巧:
1、判断:背包问题 or 完全背包问题?
- 01背包问题 - 逆序遍历背包容量(不可重复取)
- 完全背包问题 - 正序遍历背包容量(可重复取)
2、判断:组合数 or 排列数?
- 求组合数 - 外层for循环遍历物品,内层for遍历背包容量。(物品顺序固定)
- 求排列数 - 外层for遍历背包容量,内层for循环遍历物品。(物品顺序可变)
3、判断:求最大容量 or 方案数?
- 求最大容量 dp[j] = Math.max(dp[j], dp[j - nums[i]] + nums[i]); (求最大)
- 求方案数 dp[j] += dp[j-nums[i]]; (求叠加)
分析:
1、数组中的元素可以重复取,无限次数,属于完全背包问题,正序遍历背包容量。
2、顺序不同的序列被视作不同的组合,相当于求的是排列数,外层for循环遍历背包容量。
3、求的是方案数,使用叠加的公式,记得设置初始值 dp[0] = 1,否则后面全是0。
class Solution {public int combinationSum4(int[] nums, int target) {int[] dp = new int[target + 1];dp[0] = 1;// 求排列数for (int i = 0; i < target + 1; i++){ // 外层for正序遍历书包容量for (int j = 0; j < nums.length; j++){ // 内层for遍历物品if (i >= nums[j]) dp[i] += dp[i - nums[j]]; // 书包容量足够(>=)的情况下才能考虑取}}return dp[target];}
}
- 时间复杂度:O(M×N),M是target,N是nums数组的元素个数
- 空间复杂度:O(M)
这篇关于【力扣一刷】代码随想录day44(动态规划part6 - 背包问题专题: 完全背包理论基础、卡码网52、518. 零钱兑换 II、377. 组合总和 Ⅳ )的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!