代码随想录算法训练营第60期第四十二天打卡

        大家好,今天还是继续我们的动态规划里面的背包问题,前面我们主要接触的是0-1背包和完全背包,其实这两个背包问题主要就是看看每一件物品我们是否有多件,如果每一件物品我们只能取一次的话那这样我们就是0-1背包,如果每一件物品我们可以取多件的话那这样就是完全背包,那我们就接着以前的来继续我们今天的题目。

第一题对应力扣上编号为322的题目零钱兑换

          这道题大家听到题目名字应该就会有种熟悉的感觉,我们是不是前面做过,是的我们前面的确做过一道关于零钱兑换的题目,而且我们在贪心算法章节还刷过一道叫做柠檬水找零的题目,那我们看看这道题目跟我们以前做过的有什么不一样的:

        其实这道题目的背景与我们前面的那道零钱兑换的题目是一样的,不过那道题目让我们求的是可以凑出给定数额的组合方案数,而这一道题目让我们求的是凑出给定数额的所需的最少硬币个数,其实很明显题目还是很经典的完全背包问题,因为我们每种硬币的数量是无限的,但本题和纯完全背包不一样,纯完全背包是凑成背包最大价值是多少,而本题是要求凑成总金额的物品最少个数!那我们还是尝试使用完全背包问题来解决,还是动用动规五部曲。

       首先动规五部曲的第一步就是确定dp数组的含义,其实这里的话我们使用一维dp数组就可以了,dp[j]:凑足总额为j所需钱币的最少个数为dp[j]。

       第二步就是确定递推公式,我们需要仔细考虑一下,因为题目要求我们去求凑出给定金额的最少的钱币数,所以我们可以大致猜测肯定要出现取min值,我们很容易知道凑足总额为j - coins[i]的最少个数为dp[j - coins[i]],那么只需要加上一个钱币coins[i]即dp[j - coins[i]] + 1就是dp[j](考虑coins[i],那如果不考虑coins[i]呢?那就是dp[j], 那这样两个取最小值不就是我们的递推公式了。

       第三步就是初始化dp数组,我们首先凑足总金额为0所需钱币的个数一定是0,那么dp[0] = 0;

这个是很明显的,考虑到递推公式的特性,dp[j]必须初始化为一个最大的数,否则就会在min(dp[j - coins[i]] + 1, dp[j])比较的过程中被初始值覆盖。因为我们每一次都要取最小值,这样可以保证每次都可以正确更新所需的最少钱币数。

        第四步就是确定遍历顺序,本题求钱币最小个数,那么钱币有顺序和没有顺序都可以,都不影响钱币的最小个数。那其实我们先遍历钱币再遍历金额是可以的,反过来也是可以的。

        还有一步比较重要的就是举例推导dp数组,以代码随想录的例子为例:

           那我们可以尝试给出代码:

class Solution {
public:int coinChange(vector<int>& coins, int amount) {vector<int> dp(amount + 1, INT_MAX);//初始化dp数组dp[0] = 0;//先遍历钱币再遍历总额for (int i = 0; i < coins.size(); ++i){for (int j = coins[i]; j <= amount; ++j){//如果被更新了就说明存在最少的硬币数而且可以被凑出if (dp[j - coins[i]] != INT_MAX){dp[j] = min(dp[j - coins[i]] + 1, dp[j]);}}}if (dp[amount] == INT_MAX) return -1;return dp[amount];}
};

 第二题对应力扣编号为279的题目完全平方数

         这是我们今天的第二题,这道题我们以前没有见过比较类似的背景,我们就直接看看这道题目的要求:

        读完题目之后我就知道了,其实就是凑出这个数我们至少需要几个完全平方数,这个题目似乎与上一道题目比较类似,其实都是填满背包至少需要多少件物品类型题目,很明显这个题目还是完全背包,那我们还是得用动规五部曲来解决。

        第一步还是确定dp数组的含义,dp[j]:和为j的完全平方数的最少数量为dp[j]。

        第二步就是递推公式,这道题目的递推公式与上一道题目的递推公式是异曲同工,还是我们考虑我是是否使用当前的完全平方数,当然我们不需要去写一个函数判断一个数是不是完全平方数,这里的每一个数就相当于我们上一道题的钱币金额,所以我们的递推公式大家或许就知道了应该是dp[j] = min(dp[j - i * i] + 1, dp[j])。

        第三步一样的思路还是dp数组的初始化,dp[0] = 0其实这里可能有同学存在疑问,明明0*0 = 0那为啥dp[0] = 1不对呢,看题目描述,找到若干个完全平方数(比如 1, 4, 9, 16, ...),题目描述中可没说要从0开始,dp[0]=0完全是为了递推公式。所以其实这个dp[0] = 0没有什么意义,从递归公式dp[j] = min(dp[j - i * i] + 1, dp[j]);中可以看出每次dp[j]都要选最小的,所以非0下标的dp[j]一定要初始为最大值,这样dp[j]在递推的时候才不会被初始值覆盖。这里其实与我们上面的题目也是类似的。

       第四步就是确定遍历顺序,我们还是使用完全背包的思路,先遍历物品再遍历背包就可以了。

        第五步就是打印验证dp数组这里就不说了,这个大家可以自行去测试。接下来走完动规五部曲以后我们就可以写出这道题目的解题代码:

class Solution {
public:int numSquares(int n) {vector<int> dp(n + 1, INT_MAX);dp[0] = 0;//遍历物品for (int i = 1; i <= n; ++i){//遍历背包其实也就是我当前使用完全平方数和凑出来的和for (int j = i * i; j <= n; ++j){//这是我们的递推公式,如果我想用一个i * i凑出的完全平方数就得先看前面那个数的需要//完全平方数的个数然后加1就可以了dp[j] = min(dp[j - i * i] + 1, dp[j]);}}return dp[n];}
};

第三题对应力扣编号为139的题目单词拆分

       这是我们今天的最后一道题目,我们动态规划章节似乎也没有遇到过背景相似的题目,所以我们就先看看题目的要求:

       题目是给我们一个字符串列表里面存放了一些单词,给定我们一个字符串,看看这个字符串是否可以由我们字符串列表里面的单词拼接出来,而且字符串列表里面的单词都是可以重复使用的,很明显这还是一道完全背包的问题,那我们还是使用动规五部曲来解决这道题目。

      第一步确定dp数组以及下标的含义:dp[i] : 字符串长度为i的话,dp[i]为true,表示可以拆分为一个或多个在字典中出现的单词。这题目有点特殊,所以我们定义的dp数组也是有点奇怪,第一次出现过bool类型的dp数组。

       第二步就是我们的确定递推公式,这或许很奇怪,既然我们的dp数组都定义成了bool类型的那我们还有什么递推公式,其实是这样的:如果确定dp[j] 是true,且 [j, i] 这个区间的子串出现在字典里,那么dp[i]一定是true。(j < i )。这个听起来很抽象其实不难理解,我们dp[j]已经凑出了,只要我们[j,i]的区间里面存在我们长度为j与长度为i相差的字符串,那不就说明长度为i的字符串也可以被凑出了。这个思路很有趣,大家要好好积累一下。

       第三步是dp数组如何初始化,从递推公式中可以看出,dp[i] 的状态依靠 dp[j]是否为true,那么dp[0]就是递推的根基,dp[0]一定要为true,否则递推下去后面都都是false了。大家可以想想其实题目也说了我们的字符串是非空的,其实dp[0]完全是为了递推公式服务。

       第四步就是遍历顺序,这其实还是一道完全背包的题目,那我们其实还是可以按照完全背包的遍历顺序,其实单词就是物品,题目所给字符串就是背包,题目还是有需要注意的地方,这道题目是在意顺序,其实也就是排列问题而不是组合问题,如何理解?拿 s = "applepenapple", wordDict = ["apple", "pen"] 举例。"apple", "pen" 是物品,那么我们要求 物品的组合一定是 "apple" + "pen" + "apple" 才能组成 "applepenapple"。"apple" + "apple" + "pen" 或者 "pen" + "apple" + "apple" 是不可以的,那么我们就是强调物品之间顺序。所以我们就知道了这道题目我们就只能先遍历背包再遍历物品,如果我们先遍历物品再遍历背包就会出现乱序的情况,这点大家必须注意。

       那这样其实题目的代码与以前似乎还是有些不一样:

class Solution {
public:bool wordBreak(string s, vector<string>& wordDict) {unordered_set<string> wordSet(wordDict.begin(), wordDict.end());vector<bool> dp(s.size() + 1, false);dp[0] = true;for (int i = 1; i <= s.size(); i++) {   // 遍历背包for (int j = 0; j < i; j++) {       // 遍历物品string word = s.substr(j, i - j); //substr(起始位置,截取的个数)if (wordSet.find(word) != wordSet.end() && dp[j]) {dp[i] = true;}}}return dp[s.size()];}
};

 今日总结

       我们今天的题目其实有难度,大家得多多思考,理解动态规划并不容易,尤其是单词拆分这道题目的确很有难度,我们得理解为什么必须先遍历背包再遍历物品,以及我们要区分题目是考察的我们是组合问题还是排列问题,就是看看有没有顺序要求即可,这就是我们今天的讲解,我们明天见! 

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

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

相关文章

第41天-Python+Qt四屏播放器开发指南

一、技术选型与工具准备 核心库: Pyqt5:Python标准GUI库,构建用户界面 os / sys:文件系统操作 开发环境: pip install pyqt5 最终效果与运行 import sys from PyQt5.QtWidgets import QVBoxLayout, QHBoxLayout # 添加缺失的布局管理器 from PyQt5.QtCore impor…

upload-labs通关笔记-第12关 文件上传之白名单GET法

目录 一、白名单过滤 二、%00截断 1、%00截断原理 2、空字符 3、截断条件 &#xff08;1&#xff09;PHP版本 < 5.3.4 &#xff08;2&#xff09;magic_quotes_gpc配置为Off &#xff08;3&#xff09;代码逻辑存在缺陷 三、源码分析 1、代码审计 &#xff08;1&…

Node.js数据抓取技术实战示例

Node.js常用的库有哪些呢&#xff1f;比如axios或者node-fetch用来发送HTTP请求&#xff0c;cheerio用来解析HTML&#xff0c;如果是动态网页的话可能需要puppeteer这样的无头浏览器。这些工具的组合应该能满足大部分需求。 然后&#xff0c;可能遇到的难点在哪里&#xff1f;…

数据结构(3)线性表-链表-单链表

我们学习过顺序表时&#xff0c;一旦对头部或中间的数据进行处理&#xff0c;由于物理结构的连续性&#xff0c;为了不覆盖&#xff0c;都得移&#xff0c;就导致时间复杂度为O&#xff08;n&#xff09;&#xff0c;还有一个潜在的问题就是扩容&#xff0c;假如我们扩容前是10…

【Unity】DOTween的常用函数解释

DOTween插件常用函数解释 1.DOTween.To&#xff08;通用变化动画&#xff09; 解释&#xff1a;将某一个值在一定的时间内变化到另一个值&#xff08;通用的函数&#xff09;&#xff0c;可用于大部分的动画变化 使用示例&#xff1a; using UnityEngine; using DG.Tweenin…

数据结构测试模拟题(1)

1、约瑟夫问题 #include<bits/stdc.h> using namespace std; const int N25; int e[N],ne[N],head-1,idx1; int n,m; void add_to_head(int x){e[idx]x;ne[idx]head;headidx; } void add(int k,int x){e[idx]x;ne[idx]ne[k];ne[k]idx; } int main(){cin>>n>>…

Helm配置之为特定Deployment配置特定Docker仓库(覆盖全局配置)

文章目录 Helm配置之为特定Deployment配置特定Docker仓库(覆盖全局配置)需求方法1:使用Helm覆盖值方法2: 在Lens中临时修改Deployment配置步骤 1: 创建 Docker Registry Secret步骤 2: 在 Deployment 中引用 Secret参考资料Helm配置之为特定Deployment配置特定Docker仓库(覆…

BERT 作为Transformer的Encoder 为什么采用可学习的位置编码

摘要 BERT 在位置编码上与原始 Transformer 论文中的 sin/cos 公式不同&#xff0c;选择了可学习&#xff08;learned&#xff09;的位置嵌入方案。本文将从 Transformer 原始位置编码选项入手&#xff0c;分析 BERT 选择 learned positional embeddings 的四大核心原因&#x…

【Linux 学习计划】-- gcc、g++、动静态库链接

目录 什么是gcc、g gcc、g 相关操作详解 预处理、编译、汇编、链接来源 动静态链接是什么 结语 什么是gcc、g gcc、g其实就是编译器&#xff0c;是帮助我们从.c或者.cc&#xff0c;.cpp文件编译成可执行程序的 其中&#xff0c;我们如果要编译c语言文件的话&#xff0c;…

前端读取本地项目中 public/a.xlsx 文件中的数据 vue3

前端读取本地项目中 public/a.xlsx 文件中的数据 vue3 项目中需要在 Vue3 项目中读取 public/a.xlsx 文件&#xff0c;可以使用 fetch API 来获取文件内容 一、安装 xlsx 首先&#xff0c;你需要安装 xlsx 库&#xff1a; npm install xlsx二、在需要用的页面里引入xlsx im…

MySQL:to many connections连接数过多

当你遇到 MySQL: Too many connections 错误时&#xff0c;意味着当前连接数已达到 MySQL 配置的最大限制。这通常是由于并发连接过多或连接未正确关闭导致的。 一、查看当前连接数 查看 MySQL 当前允许的最大连接数 SHOW VARIABLES LIKE max_connections;查看当前使用的最大…

2024年热门AI趋势及回顾

人工智能的崛起 2024 年可能会被铭记为人工智能不再是一种技术新奇事物&#xff0c;而是成为现实的一年。微软、Salesforce 和 Intuit 等巨头将人工智能融入主流企业解决方案&#xff1b;从文案写作到数据分析&#xff0c;专门的人工智能应用程序和服务如雨后春笋般涌现&#…

LangFlow技术深度解析:可视化编排LangChain应用的新范式 -(2)流编辑器系统

Flow Editor System | langflow-ai/langflow | DeepWiki 流编辑器系统 相关源文件 流编辑器系统是 Langflow 的核心交互式组件&#xff0c;允许用户直观地创建、编辑和管理 LLM 驱动的应用程序。它提供了一个直观的画布&#xff0c;用户可以在其中添加节点、将其与边缘连接并…

驱动-定时-秒-字符设备

文章目录 目的相关资料参考实验驱动程序-timer_dev.c编译文件-Makefile测试程序-timer.c分析 加载驱动-运行测试程序总结 目的 通过定时器timer_list、字符设备、规避竞争关系-原子操作&#xff0c;综合运用 实现一个程序&#xff0c;加深之前知识的理解。 实现字符设备驱动框…

[Java实战]Spring Boot整合Kafka:高吞吐量消息系统实战(二十七)

[Java实战]Spring Boot整合Kafka&#xff1a;高吞吐量消息系统实战&#xff08;二十七&#xff09; 一、引言 Apache Kafka作为一款高吞吐量、低延迟的分布式消息队列系统&#xff0c;广泛应用于实时数据处理、日志收集和事件驱动架构。结合Spring Boot的自动化配置能力&…

Kotlin Multiplatform--04:经验总结(持续更新)

Kotlin Multiplatform--04&#xff1a;经验总结&#xff08;持续更新&#xff09; 引言 引言 本章用来记载笔者开发过程中的一些经验总结 一、Ktor设置Header 在官方文档中&#xff0c;想要设置Header的示例代码如下&#xff1a; client.get("https://ktor.io&qu…

在 Ubuntu 系统中,将 JAR 包安装为服务

在 Ubuntu 系统中&#xff0c;将 JAR 包安装为服务可以通过 systemd 来实现。以下是详细的操作步骤&#xff1a; 准备工作 确保 JAR 文件路径和 Java 运行时环境已准备好。验证 Java 是否可用&#xff1a; java -version创建 systemd 服务文件 systemd 的服务文件通常位于 …

电商项目-商品微服务-品牌管理微服务开发

一、功能分析 品牌管理微服务包括&#xff1a; &#xff08;1&#xff09;查询全部列表数据 &#xff08;2&#xff09;根据ID查询实体数据 &#xff08;3&#xff09;增加 &#xff08;4&#xff09;修改 &#xff08;5&#xff09;删除 &#xff08;6&#xff09;分页…

Spring Boot开发—— 整合Lucene构建轻量级毫秒级响应的全文检索引擎

文章目录 一、为什么选择 Lucene?轻量级搜索的底层密码二、核心原理:Lucene 的倒排索引2.1 倒排索引:速度之源2.2 段合并优化策略三、Spring Boot集成Lucene实战3.1 依赖配置3.2 实体与索引设计3.3 核心索引服务(含异常处理)3.4 使用示例(测试类)四、高级优化技巧4.1 索…

SpringBootDay1|面试题

目录 一、springboot框架 1、什么是springboot 2、Spring Boot的主要优点 3、springboot核心注解 4、定义banner&#xff08;springboot的logo&#xff09; 5、springboot配置文件 6、springboot 整合 jdbc 二、面试题 1&#xff09;springmvc的作用 ​编辑 2&#x…