Day38--动态规划--322. 零钱兑换,279. 完全平方数,139. 单词拆分,56. 携带矿石资源(卡码网),背包问题总结

Day38–动态规划–322. 零钱兑换,279. 完全平方数,139. 单词拆分,56. 携带矿石资源(卡码网),背包问题总结

今天的是几道经典的“完全背包”题目。前两道题目,要区分求的是“价值”,还是“达成价值的最大/最小数量“。最后一道题目,介绍了多重背包,其实是可以转为01背包去做。

322. 零钱兑换

思路:

  1. 确定dp含义:dp[j]:凑足总额为j所需钱币的最少个数为dp[j]

  2. 凑足总额为j - coins[i]的最少个数为dp[j - coins[i]],那么只需要加上一个钱币coins[i]dp[j - coins[i]] + 1就是dp[j]

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

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

  3. dp[0] = 0;

  4. 遍历顺序:都可以,因为求的不是排列数或者组合数。

class Solution {public int coinChange(int[] coins, int amount) {// 最大值,因为要用到Math.minint max = Integer.MAX_VALUE;int n = coins.length;// bagSize 是 amountint[] dp = new int[amount + 1];// 初始化Arrays.fill(dp, max);dp[0] = 0;// 动态规划for (int i = 0; i < n; i++) {// 多重背包,要正序for (int j = coins[i]; j <= amount; j++) {// 不等于max,才证明是由硬币组成的if (dp[j - coins[i]] != max) {// 等式左边的dp[j],是更新后的,是这一层的// 等式右边的dp[j],是更新前的,是上一层的// 等式右边的dp[j - coins[i]],在dp[j]的左边,所以是同一层的,已经更新过的// 对于`dp[j - coins[i]] + 1`这个因素,它的意思是,腾出coins[i]的空间之后,在本层找[j - coins[i]]这个位置是需要多少硬币的,+1(加上当前遍历的这枚coins[i])就是当前位置的硬币数了dp[j] = Math.min(dp[j], dp[j - coins[i]] + 1);}}// // 打印观察// for (int k = 0; k <= amount; k++) {//     System.out.print(dp[k]+" ");// }// System.out.println(" ");}return dp[amount] == max ? -1 : dp[amount];}
}

简洁版:

class Solution {public int coinChange(int[] coins, int amount) {int max = Integer.MAX_VALUE;int n = coins.length;int[] dp = new int[amount + 1];Arrays.fill(dp, max);dp[0] = 0;for (int i = 0; i < n; i++) {for (int j = coins[i]; j <= amount; j++) {if (dp[j - coins[i]] != max) {dp[j] = Math.min(dp[j], dp[j - coins[i]] + 1);}}}return dp[amount] == max ? -1 : dp[amount];}
}

279. 完全平方数

思路:

  1. 确定dp数组含义:dp[j]就是和为 j 的完全平方数的最少数量 。
  2. 递推公式:dp[j] = Math.min(dp[j], dp[j - i * i] + 1);
    • 情况一:就是等于上一层。
    • 情况二如果要等于这一层的话,先取:减去当前的数字i的平方那个位置的数量,然后加i这“一位”数,所以+1
    • 然后情况一、二取最小值。
  3. 初始化:
    • dp[0] 是无意义的,因为没有数的平方等于0。但是初始化需要dp[0] = 0;
    • 因为有了Math.min(),所以非0下标的地方要全部赋值max
  4. 遍历顺序:只要数量,那就求排列数或者组合数都可以。那就是先背包再数字,或者先数字再背包都可以。
  5. 额外的剪枝优化:可以减少遍历数量。要平方得到n,最少只需要一个根号n,所以遍历到的最大值设为√n就好。
// bagSize 是 n
// nums[] 的上限是 Math.sqrt(n);
class Solution {public int numSquares(int n) {// 需要用到Math.minint max = Integer.MAX_VALUE;// 剪枝,可以减少遍历数量。要平方得到n,最少只需要一个根号nint numsMax = (int) Math.sqrt(n);// 一维dp数组int[] dp = new int[n + 1];// 初始化Arrays.fill(dp, max);// dp[0] 是无意义的,因为没有数的平方等于0。但是初始化需要,不然是max的话,做不了了dp[0] = 0;// i从1开始for (int i = 1; i <= numsMax; i++) {// j直接从i方开始遍历,因为小于i方的数,本层都更新不了,等于上层数据for (int j = i * i; j <= n; j++) {// 肯定要min的,比如n=16,直接是1个4方就够了,而不是4个2方// 为什么是+1?遍历到了数值i了,这一层先腾空i*i的空间,再往前找dp[j - i * i]的数量,加上i这个数(这一个数),所以就是加1dp[j] = Math.min(dp[j], dp[j - i * i] + 1);}}return dp[n];}
}

139. 单词拆分

思路:

  1. dp数组含义:字符串长度为i的话,dp[i]为true,表示可以拆分为一个或多个在字典中出现的单词。
  2. 递推公式:
    • 如果这个区间是存在于字典里的一个串,这个串的开头,跟已经判断过的内容的结尾是相接的。那么这个串的末尾+1的位置给它赋值为true。
    • 如果确定dp[j] 是true(到j这里都是true),且 [j, i] 这个区间的子串出现在字典里,那么dp[i]一定是true。(j < i )。
    • 所以递推公式是 if([j, i] 这个区间的子串出现在字典里 && dp[j]是true) 那么 dp[i] = true
  3. 初始化:dp[0] = true;
  4. 遍历顺序:因为字典中的单词,可能会被重复取,所以要按照排列数的方法来做——即先遍历背包,再遍历物品。
class Solution {public boolean wordBreak(String s, List<String> wordDict) {Set<String> wordSet = new HashSet<>(wordDict);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++) { // 遍历物品String word = s.substring(j, i); //substring(起始位置,结束位置)if (wordSet.contains(word) && dp[j]) {dp[i] = true;}}}return dp[s.length()];}
}

思路:

上面的思路,是不断截取子字符串,判断是否在字典中。

还可以这样做,i往前走,遍历字典里面的所有单词,判断[i - len, i)这个区间的字符串是否跟字典里某个单词相等,是的话,当前位置设为true。(注意substring方法是左闭右开,当前i的位置已经是下一个单词的开头了。所以刚好在索引s.length()的时候,可以返回最终结果)

class Solution {public boolean wordBreak(String s, List<String> wordDict) {boolean[] dp = new boolean[s.length() + 1];dp[0] = true;for (int i = 1; i <= s.length(); i++) {for (String word : wordDict) {int len = word.length();if (i >= len && dp[i - len] && word.equals(s.substring(i - len, i))) {dp[i] = true;break;}}}return dp[s.length()];}
}

记录:这道题感觉跟常规的背包问题,忽然间不太熟悉,想了许久没出来,直接看题解,理解题目,下次二刷。

56. 携带矿石资源(卡码网)

这道题目是用来理解多重背包问题的。

多重背包的样子:

重量价值数量
物品01152
物品13203
物品24302

实际上,换个角度就变成01背包了:

重量价值数量
物品01151
物品01151
物品13201
物品13201
物品13201
物品24301
物品24301

思路:

所以就是多套一层循环,把物品i遍历对应的次数就行了。按照常规01背包的步骤来做。

import java.util.*;public class Main {public static void main(String[] args) {Scanner in = new Scanner(System.in);// 背包容量int bagSize = in.nextInt();// 一共有n种矿石int n = in.nextInt();// 每种矿石的重量int[] weight = new int[n];// 每种矿石的价值int[] value = new int[n];// 每种矿石分别有多少块int[] perAmount = new int[n];// 输入for (int i = 0; i < n; i++) {weight[i] = in.nextInt();}for (int i = 0; i < n; i++) {value[i] = in.nextInt();}for (int i = 0; i < n; i++) {perAmount[i] = in.nextInt();}// dp数组的含义:在bagSize的容量下,最大能取到的总价值int[] dp = new int[bagSize + 1];//动态规划// 遍历每种矿石for (int i = 0; i < n; i++) {// 遍历每种矿石的数量for (int per = 0; per < perAmount[i]; per++) {// 遍历背包容量for (int j = bagSize; j >= weight[i]; j--) {// 常规的01背包的递推公式dp[j] = Math.max(dp[j], dp[j - weight[i]] + value[i]);}}}// 输出结果System.out.println(dp[bagSize]);}
}

背包问题总结

最关键的两步:递推公式 + 遍历顺序

递推公式:

  • 按价值
    • 最多能装多少?
    • 能否装满?
    • 递推公式:dp[j] = max(dp[j], dp[j - nums[i]] + nums[i]);
  • 求有多少种方法?
    • 组合数
    • 排列数
    • 递推公式:dp[j] += dp[j - nums[i]]
  • 装满背包时候的最小个数
    • 题目:零钱兑换、完全平方数
    • 递推公式:dp[j] = min(dp[j - coins[i]] + 1, dp[j]);

遍历顺序:

  • 01背包:倒序(因为要左上方和正上方的数据)
  • 完全背包:正序(因为要左方和正上方的数据)
    • 求组合数:先物品,后背包
    • 求排列数:先背包,后物品
    • 求最大数、最小数:无所谓

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/92610.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/92610.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

应用层Http协议(1)

应用层Http协议&#xff08;1&#xff09; 在互联网世界中&#xff0c;HTTP&#xff08;HyperText Transfer Protocol&#xff0c;超文本传输协议&#xff09;是一个至关重要的协议。它定义了客户端&#xff08;如浏览器&#xff09;与服务器之间如何通信&#xff0c;以交换或传…

elementui input无法输入问题

背景。开发小程序。自定义表单在pc段设置好input输入框属性后。 在小程序端无法输入原因&#xff1a;长度受限制&#xff0c;导致input组件的maxlength属性认为长度是0导致无法输入任何值。看解释是应为遇到空字符串等情况会设置为0解决。因为未找到设置maxlength为0处&#xf…

算法_python_学习记录_02

算法学习和视频学习过程中&#xff0c;有许多前几天还不知道的知识点&#xff0c;现在一点一点归纳整理出来&#xff0c;稳步前进&#xff0c;前进~ 20_贪心算法系列题 00_参考文档 详解贪心算法&#xff08;Python实现贪心算法典型例题&#xff09;_顺序贪婪算法-CSDN博客P…

Meta AI水印计划的致命缺陷——IEEE Spectrum深度文献精读

一、原文信息 标题: Metas AI Watermarking Plan Is Flimsy, at Best 中文译名: Meta的AI水印计划脆弱不堪 作者: David Evan Harris(加州大学伯克利分校)、Lawrence Norden(纽约大学法学院) 发表日期: 2024年3月5日 发表期刊: IEEE Spectrum 二、原文全文翻译 Met…

gpt-oss 全量技术解读

一、概述 gpt-oss 是 OpenAI 发布的开放权重&#xff08;open-weight&#xff09;模型系列&#xff0c;面向强推理、Agent 能力与多样化应用场景。 提供两种规格&#xff1a; gpt-oss-120b&#xff1a;面向生产与高推理需求&#xff0c;单卡 80GB GPU&#xff08;如 NVIDIA …

实现EtherNet/IP网络与Modbus TCP网络之间数据互通

硬件连接与配置使用工业以太网网关&#xff08;如ENE-350&#xff09;作为桥接设备&#xff0c;通过以太网交换机实现硬件互联。 网关需根据应用场景配置为EtherNet/IP从站或Modbus TCP主/从站模式。案例1&#xff1a;EtherNet IP主站PLC和Modbus TCP主站PLC的互联网关配置&…

zookeeper因jute.maxbuffer启动异常问题排查处理

#作者&#xff1a;程宏斌 文章目录一、前言二、问题描述三、定位过程四、问题根因五、解决方案根本解决方案应急处理方案调大参数可能出现的问题六、总结为什么超出会报错官方对于jute.maxbuffer的解释注意事项官方建议一、前言 在分布式系统中&#xff0c;ZooKeeper作为关键的…

Java基础十三: List

目录 1.Java LinkedList 的高级应用与示例 1.1 LinkedList的基本使用 基本操作示例 1.2 LinkedList独有的方法 特定方法示例 1.3 队列模式&#xff08;先进先出&#xff09; 队列模式示例 1.4 栈模式&#xff08;先进后出&#xff09; 栈模式示例 总结 2.Java Vecto…

[机器学习]03-基于核密度估计(KDE)的鸢尾花数据集分类

关键点&#xff1a;使用核密度估计&#xff08;KDE&#xff09; 估计类别条件概率密度&#xff08;高斯核&#xff0c;带宽0.2&#xff09;采用最大后验概率&#xff08;MAP&#xff09; 决策准则进行分类程序代码&#xff1a;import random import matplotlib from sklearn.ne…

jmeter怎么实现多个请求真正的同时发送

1.首先在插件管理器Plugins Manager中搜索插件Parallel Controller&Sampler&#xff0c;勾选上对应的插件后&#xff0c;在右下角点击Apply Changes and Restart JMeter&#xff0c;安装插件2.插件安装完毕后&#xff0c;然后在线程组上面右击&#xff0c;点击添加--逻辑控…

复杂环境下车牌识别准确率↑29%:陌讯动态特征融合算法实战解析

原创声明本文为原创技术解析&#xff0c;核心技术参数与架构设计引用自《陌讯技术白皮书》&#xff0c;转载需注明来源。一、行业痛点&#xff1a;车牌识别的现实挑战在智慧交通、停车场管理等场景中&#xff0c;车牌识别作为关键技术环节&#xff0c;长期面临多重环境干扰。据…

Express中间件和路由及响应方法

1.中间件分类 应用程序级别中间件 通过 app.use() 或 app.METHOD()&#xff08;如 app.get&#xff09;绑定的中间件&#xff0c;作用于整个应用程序。例如 记录请求日志、解析请求体等全局功能。例如&#xff1a; app.use((req, res, next) > {console.log(Request URL:…

Dokcer创建中间件环境

简而言之&#xff0c;用docker来搞中间件环境比价好使&#xff0c;不用关心各种环境了 rabbitmqsudo docker run -d \--name rabbitmq \-p 5672:5672 \-p 15672:15672 \rabbitmq:3.8-managementredis 5.0.3 docker start my-redisdocker run --name my-redis -d -p 6379:6379 \…

Linux高级编程-文件操作

1.Linux下的文件类型7种文件类型&#xff1a;b 块设备文件 -------> 存储类设备&#xff08;硬盘&#xff09; c 字符设备文件 ------->如输入输出设备&#xff08;鼠标键盘显示器...&#xff09; d 目录文件 ------->文件夹 - 普通文件 -------&g…

web:vue中import *** from 和import {***} from的区别

在Vue.js中,import语句用于导入模块、组件或变量等。使用带花括号{}和不带花括号的区别主要在于导入的内容是具名导出(named exports)还是默认导出(default export)。 默认导入 (Default Import) - 不带花括号 import Vue from vue; import MyComponent from ./MyCompone…

Mysql如何优化my.conf配置文件?

优化 MySQL 的 my.cnf 配置文件&#xff0c;可以显著提升数据库性能&#xff0c;特别是在高并发或大数据量场景下。以下是优化 my.cnf 的方法和建议&#xff0c;涵盖 常见配置项、参数说明 和 优化技巧。1. 优化前的准备工作在修改 my.cnf 之前&#xff0c;需了解以下内容&…

Cherryusb UAC例程对接STM32内置ADC和DAC播放音乐和录音(上)=>TIM+DAC+ADC+DMA正弦波回环测试

0. 概述 文本目标基于Cherryusb官方例程audio_v1_mic_speaker_multichan_template.c&#xff0c;底层对接STM32的内置ADC和DAC&#xff0c;实现录音和播放。通过电脑播放歌曲&#xff0c;板子发出声音。通过电脑录音机开启录音&#xff0c;板子作为麦克风采集声音&#xff0c;…

数模个人笔记

写在前面&#xff1a;不建议观看&#xff0c;会烂尾的1.马氏链&#xff1a;状态空间指的是随机变量的取值范围&#xff0c;xi称为一个状态&#xff0c;应用背景在现在的条件下下一状态发生的概率&#xff0c;比如退火&#xff0c;他的条件概率可化简为&#xff1a;且nm时刻的概…

Spring Boot自定义Starter:从原理到实战全解析

1. 背景与需求1.1 什么是Starter&#xff1f; Spring Boot的起步依赖&#xff08;Starter&#xff09;是一种特殊的依赖描述符&#xff0c;用于简化Spring应用的依赖管理和自动配置。官方文档将Starter定义为“一组方便的依赖描述符”&#xff0c;开发者只需引入对应的Starter&…

安宝特方案丨工业AR+AI质检方案:致力于提升检测精度与流程效率

据IDC预测&#xff0c;2025年中国工业AI质检市场规模将达62亿元&#xff0c;年复合增长率28.5%&#xff0c;新能源、消费电子、高端装备三大领域贡献超70%市场份额。这一数据印证了AI质检已从可选技术升级为制造业降本增效的生存刚需。当前制造业质检环节正面临&#xff1a;精度…