通俗的方式解释“零钱兑换”问题

“零钱兑换”是一道经典的算法题目,其主要问题是:给定不同面额的硬币和一个总金额,求出凑成总金额所需的最少硬币个数。如果没有任何一种硬币组合能组成总金额,返回-1。

解题思路

  1. 动态规划:使用动态规划是解决零钱兑换问题的常用方法。定义一个数组dp,其中dp[i]表示凑成金额i所需的最少硬币个数。
  2. 状态转移方程:对于每个金额i,遍历所有硬币面额coin,如果i >= coin,则dp[i] = min(dp[i], dp[i - coin] + 1)
  3. 初始化dp[0] = 0,因为凑成金额0不需要任何硬币。对于其他金额,可以初始化为一个较大的数(如amount + 1),表示初始时无法凑成该金额。
  4. 结果判断:最终dp[amount]即为所求,如果dp[amount]仍为初始值,则表示无法凑成总金额,返回-1。

示例代码(C++)

#include <vector>
#include <algorithm>
using namespace std;int coinChange(vector<int>& coins, int amount) {vector<int> dp(amount + 1, amount + 1); // 初始化为一个较大的数dp[0] = 0; // 凑成金额0不需要任何硬币for (int i = 1; i <= amount; ++i) {for (int coin : coins) {if (i >= coin) {dp[i] = min(dp[i], dp[i - coin] + 1);}}}return dp[amount] > amount ? -1 : dp[amount];
}

说明

  • 输入coins是一个整数数组,表示不同面额的硬币;amount是一个整数,表示总金额。
  • 输出:返回凑成总金额所需的最少硬币个数,如果无法凑成,则返回-1。

这道题考察了动态规划的思想和实现能力,是面试中常见的算法题。

状态转移方程不太懂

好的,我们来详细解释一下“零钱兑换”问题中的状态转移方程

问题背景

假设我们有若干种硬币,每种硬币有不同的面额。现在需要凑出一个总金额 amount,目标是用最少的硬币数量凑出这个金额。

动态规划中的状态定义

在动态规划中,我们需要定义一个状态来表示问题的子问题。对于零钱兑换问题,我们定义:

  • dp[i] 表示凑成金额 i 所需的最少硬币数量。

状态转移方程的含义

状态转移方程是动态规划的核心,它描述了如何从已知的子问题状态推导出当前问题的状态。

对于零钱兑换问题,状态转移方程是:
dp[i] = min(dp[i], dp[i - coin] + 1)

这个方程的意思是:

  • 如果我们想凑成金额 i,可以尝试用一个面额为 coin 的硬币。
  • 如果用了这个硬币,那么剩下的金额就是 i - coin
  • 我们已经知道凑成金额 i - coin 所需的最少硬币数量是 dp[i - coin]
  • 因此,凑成金额 i 的硬币数量可以是 dp[i - coin] + 1+1 是因为我们多用了一个硬币)。
  • 但是,凑成金额 i 的方法可能有多种(比如可以用不同面额的硬币),所以我们要取所有可能方法中的最小值。

具体例子

假设硬币面额为 [1, 2, 5],目标金额是 11

初始化

我们先初始化一个数组 dp,长度为 amount + 1,并将所有值设为一个较大的数(比如 amount + 1),表示初始时认为凑不出这些金额。同时,dp[0] = 0,因为凑成金额 0 不需要任何硬币。

计算过程

我们逐步计算每个金额的最少硬币数:

  1. 计算 dp[1]

    • 尝试用面额为 1 的硬币:dp[1 - 1] + 1 = dp[0] + 1 = 0 + 1 = 1
    • 因此,dp[1] = 1
  2. 计算 dp[2]

    • 尝试用面额为 1 的硬币:dp[2 - 1] + 1 = dp[1] + 1 = 1 + 1 = 2
    • 尝试用面额为 2 的硬币:dp[2 - 2] + 1 = dp[0] + 1 = 0 + 1 = 1
    • 因此,dp[2] = min(2, 1) = 1
  3. 计算 dp[3]

    • 尝试用面额为 1 的硬币:dp[3 - 1] + 1 = dp[2] + 1 = 1 + 1 = 2
    • 尝试用面额为 2 的硬币:dp[3 - 2] + 1 = dp[1] + 1 = 1 + 1 = 2
    • 因此,dp[3] = min(2, 2) = 2
  4. 计算 dp[4]

    • 尝试用面额为 1 的硬币:dp[4 - 1] + 1 = dp[3] + 1 = 2 + 1 = 3
    • 尝试用面额为 2 的硬币:dp[4 - 2] + 1 = dp[2] + 1 = 1 + 1 = 2
    • 因此,dp[4] = min(3, 2) = 2
  5. 计算 dp[5]

    • 尝试用面额为 1 的硬币:dp[5 - 1] + 1 = dp[4] + 1 = 2 + 1 = 3
    • 尝试用面额为 2 的硬币:dp[5 - 2] + 1 = dp[3] + 1 = 2 + 1 = 3
    • 尝试用面额为 5 的硬币:dp[5 - 5] + 1 = dp[0] + 1 = 0 + 1 = 1
    • 因此,dp[5] = min(3, 3, 1) = 1

……以此类推,直到计算出 dp[11]

总结

状态转移方程 dp[i] = min(dp[i], dp[i - coin] + 1) 的含义是:

  • 对于每个金额 i,尝试用每一种硬币 coin
  • 如果用了这个硬币,那么剩下的金额是 i - coin,而凑成 i - coin 的最少硬币数是已知的(dp[i - coin])。
  • 因此,凑成金额 i 的硬币数可以是 dp[i - coin] + 1
  • 最后取所有可能方法中的最小值,作为凑成金额 i 的最少硬币数。

希望这个解释能帮助你更好地理解状态转移方程!

我还是不理解

好的,我来用更通俗的方式解释“零钱兑换”问题。


问题背景

假设你是一名收银员,顾客需要找零,你手上有不同面额的硬币。你的任务是用最少的硬币数量凑出顾客需要的零钱金额。

举个例子

假设你手上有以下几种硬币:

  • 1元硬币
  • 3元硬币
  • 4元硬币

现在顾客需要找零 10元,你会怎么凑呢?


思考过程

  1. 目标:用最少的硬币凑出10元。
  2. 方法:你可以尝试不同的组合:
    • 用10个1元硬币(10个硬币)
    • 用3个3元硬币 + 1个1元硬币(4个硬币)
    • 用2个4元硬币 + 2个1元硬币(4个硬币)
    • 用1个4元硬币 + 2个3元硬币(3个硬币)

经过比较,你会发现 1个4元硬币 + 2个3元硬币 是最优解,只需要 3个硬币


零钱兑换问题的核心

  1. 输入

    • 一个硬币数组,比如 [1, 3, 4],表示你手上的硬币面额。
    • 一个目标金额,比如 10,表示需要凑出的金额。
  2. 输出

    • 返回最少需要的硬币数量。如果无法凑出目标金额,返回 -1
  3. 难点

    • 你不能简单地从最大的硬币开始凑,因为可能无法凑出目标金额。比如,目标金额是 6元,硬币面额是 [4, 3, 1],如果你先用一个4元硬币,剩下的2元就无法凑出(因为没有2元硬币)。

动态规划的思路

动态规划是一种分步解决问题的方法,它把大问题拆成小问题,逐步求解。

  1. 定义状态

    • 假设 dp[i] 表示凑出金额 i 所需的最少硬币数量。
  2. 状态转移

    • 假设你已经知道凑出金额 i - coin 所需的最少硬币数量(dp[i - coin]),那么加上一个面额为 coin 的硬币,就可以凑出金额 i
    • 所以,dp[i] = min(dp[i], dp[i - coin] + 1),意思是:凑出金额 i 的最少硬币数,要么是之前已经计算好的值,要么是凑出金额 i - coin 的硬币数加1。
  3. 初始化

    • dp[0] = 0,因为凑出金额0不需要任何硬币。
    • 其他金额可以初始化为一个很大的数(比如 amount + 1),表示目前无法凑出。
  4. 最终结果

    • 如果 dp[amount] 仍然是初始值(比如 amount + 1),说明无法凑出目标金额,返回 -1
    • 否则,返回 dp[amount]

用例子解释动态规划

假设硬币面额是 [1, 3, 4],目标金额是 6,我们逐步计算 dp 数组:

金额(i)0123456
dp[i]0121122
  • 金额0dp[0] = 0,凑出金额0不需要硬币。
  • 金额1:只能用1个1元硬币,所以 dp[1] = 1
  • 金额2:只能用2个1元硬币,所以 dp[2] = 2
  • 金额3:可以用3个1元硬币(dp[3] = dp[0] + 1 = 1),也可以用1个3元硬币(dp[3] = 1)。
  • 金额4:可以用4个1元硬币(dp[4] = dp[0] + 1 = 1),也可以用1个4元硬币(dp[4] = 1)。
  • 金额5:可以用5个1元硬币(dp[5] = dp[0] + 1 = 2),也可以用1个3元硬币 + 2个1元硬币(dp[5] = dp[2] + 1 = 2)。
  • 金额6:可以用6个1元硬币(dp[6] = dp[0] + 1 = 2),也可以用2个3元硬币(dp[6] = dp[0] + 2 = 2)。

最终,凑出金额6最少需要2个硬币。


总结

零钱兑换问题的核心是用最少的硬币凑出目标金额。动态规划通过逐步计算每个金额所需的最少硬币数,最终得到答案。希望这个解释能帮助你理解!

这回我终于懂了!

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

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

相关文章

GBT32960 协议编解码器的设计与实现

GBT32960 协议编解码器的设计与实现 引言 在车联网领域&#xff0c;GBT32960 是一个重要的国家标准协议&#xff0c;用于新能源汽车与监控平台之间的数据交互。本文将详细介绍如何使用 Rust 实现一个高效可靠的 GBT32960 协议编解码器。 整体架构 编解码器的核心由三个主要组…

Halcon 车牌识别-超精细教程

车牌示例 流程: 读取图片转灰度图阈值分割,找车牌内容将车牌位置设置变换区域形状找到中心点和弧度利用仿射变换,斜切车牌旋转转正,把车牌抠出来利用形态学操作拼接车牌号数字训练ocr开始识别中文车牌 本文章用到的算子(解析) Halcon 算子-承接车牌识别-CSDN博客 rgb1_to_gray…

UDP透传程序

UDP透传程序 本脚本用于在 设备 A 和 设备 B 之间建立 UDP 数据转发桥梁&#xff0c;适用于 A 和 B 设备无法直接通信的情况。 流程&#xff1a; A --> 电脑 (中继) --> B B --> 电脑 (中继) --> A 需要修改参数&#xff1a; B_IP “192.168.1.123” # 设备 B 的…

Holtek HT82V42A深度解析:CCD/CIS信号处理的集成化解决方案

——简化图像采集系统设计的终极利器 一、HT82V42A核心参数与外设资源 HT82V42A是Holtek专为图像传感器信号处理设计的模拟前端芯片&#xff0c;集成CCD/CIS信号处理与LED驱动功能&#xff0c;关键参数如下&#xff1a; 参数类别规格说明信号处理通道单通道CCD/CIS模拟信号输…

详细分析KeepAlive的基本知识 并缓存路由(附Demo)

目录 前言1. 基本知识2. Demo2.1 基本2.2 拓展2.3 终极 3. 实战 前言 &#x1f91f; 找工作&#xff0c;来万码优才&#xff1a;&#x1f449; #小程序://万码优才/r6rqmzDaXpYkJZF 基本知识推荐阅读&#xff1a;KeepAlive知识点 从实战中学习&#xff0c;源自实战中vue路由的…

记一次误禁用USB导致键盘鼠标失灵的修复过程

背景说明 在电脑上插入了一个USB hub&#xff0c;然后弹窗提示&#xff1a;“集线器端口上出现电涌”&#xff0c;点开让选择“重置”或者“关闭”&#xff0c;不小心点了关闭&#xff0c;结果这个usb口就被关了&#xff0c;再插任何东西都没反应&#xff0c;找了很多办法都恢…

小米手机如何录制屏幕?手机、电脑屏幕录制方法分享

大家最近有没有遇到想记录手机屏幕操作的情况&#xff1f; 比如精彩的游戏瞬间、有趣的视频教程&#xff0c;或者需要录制屏幕来制作演示材料。小米手机在这方面可是个好帮手&#xff0c;今天就来给你好好唠唠&#xff0c;小米手机如何录制屏幕&#xff0c;以及后续如何处理这…

如何将JAR交由Systemctl管理?

AI越来越火了&#xff0c;我们想要不被淘汰就得主动拥抱。推荐一个人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;最重要的屌图甚多&#xff0c;忍不住分享一下给大家。点击跳转到网站 废话不多说&#xff0c;进入正题。下面开始说如何使用 systemctl…

chrome Vue.js devtools 提示不支持该扩展组件,移除

可能是版本不兼容&#xff0c;可以重新安装&#xff0c;推荐网址极简插件官网_Chrome插件下载_Chrome浏览器应用商店 直接搜索vue&#xff0c;下载旧版&#xff0c;vue2、vue3都支持&#xff0c;上面那个最新版本试了下&#xff0c;vue2的肯定是不能用

【RabbitMQ】RabbitMQ的核心概念与七大工作模式

&#x1f525;个人主页&#xff1a; 中草药 &#x1f525;专栏&#xff1a;【中间件】企业级中间件剖析 在现代分布式系统和微服务架构中&#xff0c;消息队列&#xff08;Message Queue&#xff09; 是解决服务间通信、系统解耦和流量削峰的关键技术之一。而 RabbitMQ 作为一…

SQLAlchemy系列教程:理解SQLAlchemy元数据

SQLAlchemy是Python开发人员的强大ORM工具。SQLAlchemy中的元数据是对象-关系映射配置的集合&#xff0c;允许开发人员无缝地定义和使用数据库模式。 使用元数据 SQLAlchemy中的元数据充当各种数据库描述符&#xff08;如表、列和索引&#xff09;的容器。这使开发人员能够通…

MacDroid for Mac v2.3 安卓手机文件传输助手 支持M、Intel芯片 4.7K

MacDroid 是Mac毒搜集到的一款安卓手机文件传输助手&#xff0c;在Mac和Android设备之间传输文件。您只需要将安卓手机使用 USB 连接到 Mac 电脑上即可将安卓设备挂载为本地磁盘&#xff0c;就像编辑mac磁盘上的文件一样编辑安卓设备上的文件&#xff0c;MacDroid支持所有 Andr…

Android+SpringBoot的老年人健康饮食小程序平台

感兴趣的可以先收藏起来&#xff0c;还有大家在毕设选题&#xff0c;项目以及论文编写等相关问题都可以给我留言咨询&#xff0c;我会一一回复&#xff0c;希望帮助更多的人。 系统介绍 我将从经济、生活节奏、技术融合等方面入手&#xff0c;详细阐述居家养老管理模式兴起的…

【星云 Orbit • STM32F4】10. 在串口接收中断里即时解析数据头的程序框架

【星云 Orbit • STM32F4】10. 串口中断中即时解析数据头的程序开发&#xff1a;实现高效实时数据处理 摘要 在嵌入式开发中&#xff0c;串口中断处理是实现高效实时数据传输的关键技术之一。本文将详细介绍如何在STM32F407微控制器上开发一个在串口接收中断中即时解析数据头的…

数据仓库的特点

数据仓库的主要特点可以概括为&#xff1a;面向主题、集成性、非易失性、时变性、高性能和可扩展性、支持复杂查询和分析、分层架构以及数据质量管理。 1. 面向主题&#xff08;Subject-Oriented&#xff09; 数据仓库是面向主题的&#xff0c;而不是面向事务的。这意味着数据…

SAP MDG —— MDG on S/4HANA 2023 FPS03 创新汇总

文章目录 MDG 基于SAP S/4HANA 2023 FPS03的创新BP/C/S&#xff1a;消息控制BP/C/S&#xff1a;手工分配数据控制者MDG-F&#xff1a;使用S/4扩展数据校验功能生成式AI可用于协助自定义对象的数据变更/同时可总结批量变更的内容 MDG 基于SAP S/4HANA 2023 FPS03的创新 由于从S…

抽奖系统(从0-1)(上)

hu项目的开发流程介绍 1. 项目启动阶段 • 项⽬概述&#xff1a;介绍项⽬的背景、⽬标和预期成果。 • 团队组建&#xff1a;建跨职能团队&#xff0c;包括产品经理、UI/UX 设计师、开发⼈员、测试⼈员等。 • ⻆⾊定义&#xff1a;明确团队中各个⻆⾊的职责和⼯作内容。 2. 需…

vim 调整字体

vim: 在vim 面板单击右键&#xff0c;选择references: terminal :也是单击右键,选择references:

UniApp 使用 u-loadmore 完整步骤

文章目录 一、前期准备1. 安装 uView - UI 二、使用 u-loadmore组件1. 创建页面2. 编写页面代码模板部分&#xff08;loadmore-demo.vue&#xff09;样式部分脚本部分 三、要点补充1. u-loadmore 状态说明2. 数据请求优化3. 性能优化4. 兼容性问题 在 UniApp 开发中&#xff0c…

Libgdx游戏开发系列教程(3)——通过柏林噪音算法地图随机地形

在B站刷到了随机地图生成的视频,随手学习下并做下记录 注: 本篇使用javafx应用作演示,算是了解这个算法的使用,后续会再出篇libgdx生成地图的示例 说明 抛开算法实现,首先认知柏林噪音算法 一般我们想要随机数,会指定个范围,如0.0-1.0之间任意小数,而柏林算法的结果范围就是[…