Day41——Dp专题

news/2024/11/27 18:26:09/

文章目录

    • 四、完全背包
        • 01背包的核心代码
        • 完全背包的核心代码
      • 12、零钱兑换 II
      • 13、组合总和 Ⅳ


四、完全背包

完全背包:每一个物品可以选无限次

完全背包和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背包内嵌的循环是从大到小遍历,为了保证每个物品仅被添加一次。

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

完全背包的核心代码

// 先遍历物品,再遍历背包
for(int i = 0; i < weight.size(); i++) { // 遍历物品for(int j = weight[i]; j <= bagWeight ; j++) { // 遍历背包容量dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);}
}
  • 在一维数组中,01背包问题必须先遍历物品,后遍历背包。完全背包两个for循环嵌套顺序是无所谓的
  • 在一维数组中,01背包问题遍历背包时必须倒序遍历。完全背包正序遍历
  • 倒序遍历,必须先遍历物品,再遍历背包。正序遍历,则for循环嵌套顺序无所谓

Code

//先遍历物品,再遍历背包
private static void testCompletePack(){int[] weight = {1, 3, 4};int[] value = {15, 20, 30};int bagWeight = 4;int[] dp = new int[bagWeight + 1];for (int i = 0; i < weight.length; i++){ // 遍历物品for (int j = weight[i]; j <= bagWeight; j++){ // 遍历背包容量dp[j] = Math.max(dp[j], dp[j - weight[i]] + value[i]);}}for (int maxValue : dp){System.out.println(maxValue + "   ");}
}//先遍历背包,再遍历物品
private static void testCompletePackAnotherWay(){int[] weight = {1, 3, 4};int[] value = {15, 20, 30};int bagWeight = 4;int[] dp = new int[bagWeight + 1];for (int i = 1; i <= bagWeight; i++){ // 遍历背包容量for (int j = 0; j < weight.length; j++){ // 遍历物品if (i - weight[j] >= 0){dp[i] = Math.max(dp[i], dp[i - weight[j]] + value[j]);}}}for (int maxValue : dp){System.out.println(maxValue + "   ");}
}

12、零钱兑换 II

力扣题目链接

  • 组合不强调元素之间的顺序,排列强调元素之间的顺序

思路

动规五部曲

  • 确定dp数组以及下标的含义

dp[j]:凑成总金额j的货币组合数为dp[j]

  • 确定递推公式

dp[j] 就是所有的dp[j - coins[i]](考虑coins[i]的情况)相加。

所以递推公式:dp[j] += dp[j - coins[i]];

  • dp数组初始化

首先dp[0]一定要为1,dp[0] = 1是 递归公式的基础,下标非0的dp[j]初始化为0,这样累计加dp[j - coins[i]]的时候才不会影响真正的dp[j]

  • 确定遍历顺序

求组合数,先遍历物品,再遍历背包

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

求排列数,先遍历背包,再遍历物品

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]];}
}
  • 举例推导dp数组

image-20221208190623089

  • 如果求组合数就是外层for循环遍历物品,内层for遍历背包

  • 如果求排列数就是外层for遍历背包,内层for循环遍历物品

Code

class Solution {public int change(int amount, int[] coins) {//递推表达式int[] dp = new int[amount + 1];//初始化dp数组,表示金额为0时只有一种情况,也就是什么都不装dp[0] = 1;for (int i = 0; i < coins.length; i++) {for (int j = coins[i]; j <= amount; j++) {dp[j] += dp[j - coins[i]];}}return dp[amount];}
}

13、组合总和 Ⅳ

力扣题目链接

本题与零钱兑换差别就在于物品和背包的遍历顺序

动规五部曲

  • 确定dp数组以及下标的含义

dp[i]: 凑成目标正整数为i的排列个数为dp[i]

  • 确定递推公式

dp[i] += dp[i - nums[j]];

  • dp数组如何初始化

dp[0] = 1

  • 确定遍历顺序

如果求组合数就是外层for循环遍历物品,内层for遍历背包。

如果求排列数就是外层for遍历背包,内层for循环遍历物品。

遍历顺序:target(背包)放在外循环,将nums(物品)放在内循环,内循环从前到后遍历

  • 举例推导dp数组

image-20221208192928500

Code

class Solution {public int combinationSum4(int[] nums, int target) {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];}
}

http://www.ppmy.cn/news/2640.html

相关文章

C++数学表达式库(ExprTk)

一、简介 之前写了一篇c 调用python的方式实现表达式计算 &#xff0c;但在项目应用中发现单线程没问题&#xff0c;多个线程时偶尔会闪退崩溃。后面发现了一个C代码编写的表达式计算工具ExprTK, 也能同样满足需求&#xff0c;在此分享给大家。c数学表达式库&#xff08;ExprTk…

Tomcat的安装和运行

安装Tomcat 安装某一个软件,我们当然是要去官网.为了防止很多朋友找不到资源,我们这里直接放出官网路径. https://tomcat.apache.org/download-80.cgi 直接点击进入官网下载页面即可.选择Tomcat8,点击Core的zip包下载即可. 下载好以后,我们进入到下载的目录.选择到 我们下载…

DataLoader,DataSet和Sampler

DataLoader、DataSet和Sampler之间的关系 Sample和DataSet是DataLoader的两个子模块。Sampler的功能主要是生成索引。也就是样本的序号。 DatasetDatasetDataset是根据索引去读取数据以及对应的标签。DataLoader负责以特定的方式从数据集中迭代的产生一个一个batchbatchbatch集…

黑马程序员14套经典IT教程+面试宝典

很多同学对互联网比较感兴趣 &#xff0c;奈何苦恼不知道如何入门。今天免费给大家分享一波&#xff0c;黑马程序员14套经典IT教程程序员面试宝典&#xff01;涉及Java、前端、Python、大数据、软件测试、UI设计、新媒体短视频等。从厌学到学嗨&#xff0c;你只差一套黑马教程&…

如何自定义SpringBoot中的starter,并且使用它

目录 1 简介 2 规范 2.1 命名 2.2 模块划分 3 示例 1 简介 SpringBoot中的starter是一种非常重要的机制&#xff0c;能够抛弃以前繁琐的配置&#xff0c;将其统一集成进starter&#xff0c;应用者只需要在maven中引入starter依赖&#xff0c;SpringBoot就自动扫描到要加载…

Java线程实现

内容引用自《深入理解Java虚拟机&#xff1a;JVM高级特性与最佳实践&#xff08;第3版&#xff09;周志明》 线程的实现 我们知道&#xff0c;线程是比进程更轻量级的调度执行单位&#xff0c;线程的引入&#xff0c;可以把一个进程的资源分配和 执行调度分开&#xff0c;各个…

大学电子系C++模拟考试

随手附上一些代码&#xff0c;未必是最优解&#xff0c;仅供参考。 加密四位数 【问题描述】 输入一个四位数&#xff0c;将其加密后输出。方法是将该数每一位的数字加9&#xff0c;然后除以10取余作为该位上的新数字&#xff0c;最后将千位上的数字和十位上的数字互换&#…

Hbase和Mysql存储数据量对比

目录 前言 生成数据 转换成hbase能够识别的HFile文件 导入HFile到hbase中 导入数据到Mysql 总结 前言 由于想知道hbase和mysql存储同样的一份数据需要的存储是否一样&#xff0c;故做的一下实验。 生成数据 脚本如下&#xff1a; #!/bin/basharray_brand([1]huawei […