相信很多小伙伴刷题的时候面对力扣上近两千道题目,感觉无从下手,我花费半年时间整理了Github项目:leetcode刷题攻略。 里面有100多道经典算法题目刷题顺序、配有40w字的详细图解,常用算法模板总结,以及难点视频讲解,按照list一道一道刷就可以了!star支持一波吧!

322. 零钱兑换

题目链接:https://leetcode-cn.com/problems/coin-change/

给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。

你可以认为每种硬币的数量是无限的。

示例 1:
输入:coins = [1, 2, 5], amount = 11
输出:3
解释:11 = 5 + 5 + 1

示例 2:
输入:coins = [2], amount = 3
输出:-1

示例 3:
输入:coins = [1], amount = 0
输出:0

示例 4:
输入:coins = [1], amount = 1
输出:1

示例 5:
输入:coins = [1], amount = 2
输出:2

提示:

  • 1 <= coins.length <= 12
  • 1 <= coins[i] <= 2^31 - 1
  • 0 <= amount <= 10^4

思路

在动态规划:518.零钱兑换II中我们已经兑换一次零钱了,这次又要兑换,套路不一样!

题目中说每种硬币的数量是无限的,可以看出是典型的完全背包问题。

动规五部曲分析如下:

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

dp[j]:凑足总额为j所需钱币的最少个数为dp[j]

  1. 确定递推公式

得到dp[j](考虑coins[i]),只有一个来源,dp[j - coins[i]](没有考虑coins[i])。

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

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

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

  1. dp数组如何初始化

首先凑足总金额为0所需钱币的个数一定是0,那么dp[0] = 0;

其他下标对应的数值呢?

考虑到递推公式的特性,dp[j]必须初始化为一个最大的数,否则就会在min(dp[j - coins[i]] + 1, dp[j])比较的过程中被初始值覆盖。

所以下标非0的元素都是应该是最大值。

代码如下:

vector<int> dp(amount + 1, INT_MAX);
dp[0] = 0;
  1. 确定遍历顺序

本题求钱币最小个数,那么钱币有顺序和没有顺序都可以,都不影响钱币的最小个数。

所以本题并不强调集合是组合还是排列。

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

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

在动态规划专题我们讲过了求组合数是动态规划:518.零钱兑换II,求排列数是动态规划:377. 组合总和 Ⅳ。

所以本题的两个for循环的关系是:外层for循环遍历物品,内层for遍历背包或者外层for遍历背包,内层for循环遍历物品都是可以的!

那么我采用coins放在外循环,target在内循环的方式。

本题钱币数量可以无限使用,那么是完全背包。所以遍历的内循环是正序

综上所述,遍历顺序为:coins(物品)放在外循环,target(背包)在内循环。且内循环正序。

  1. 举例推导dp数组

以输入:coins = [1, 2, 5], amount = 5为例

dp[amount]为最终结果。

C++代码

以上分析完毕,C++ 代码如下:

// 版本一
class Solution {
public:int coinChange(vector<int>& coins, int amount) {vector<int> dp(amount + 1, INT_MAX);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 - coins[i]]是初始值则跳过dp[j] = min(dp[j - coins[i]] + 1, dp[j]);}}}if (dp[amount] == INT_MAX) return -1;return dp[amount];}
};

对于遍历方式遍历背包放在外循环,遍历物品放在内循环也是可以的,我就直接给出代码了

// 版本二
class Solution {
public:int coinChange(vector<int>& coins, int amount) {vector<int> dp(amount + 1, INT_MAX);dp[0] = 0;for (int i = 1; i <= amount; i++) {  // 遍历背包for (int j = 0; j < coins.size(); j++) { // 遍历物品 if (i - coins[j] >= 0 && dp[i - coins[j]] != INT_MAX ) {dp[i] = min(dp[i - coins[j]] + 1, dp[i]);}}}if (dp[amount] == INT_MAX) return -1;return dp[amount];}
};

总结

细心的同学看网上的题解,可能看一篇是遍历背包的for循环放外面,看一篇又是遍历背包的for循环放里面,看多了都看晕了,到底两个for循环应该是什么先后关系。

能把遍历顺序讲明白的文章几乎找不到!

这也是大多数同学学习动态规划的苦恼所在,有的时候递推公式很简单,难在遍历顺序上!

但最终又可以稀里糊涂的把题目过了,也不知道为什么这样可以过,反正就是过了,哈哈

那么这篇文章就把遍历顺序分析的清清楚楚。

动态规划:518.零钱兑换II中求的是组合数,动态规划:377. 组合总和 Ⅳ中求的是排列数。

而本题是要求最少硬币数量,硬币是组合数还是排列数都无所谓!所以两个for循环先后顺序怎样都可以!

这也是我为什么要先讲518.零钱兑换II 然后再讲本题即:322.零钱兑换,这是Carl的良苦用心那。

相信大家看完之后,对背包问题中的遍历顺序又了更深的理解了。

我是程序员Carl,可以找我组队刷题,也可以在B站上找到我,关注公众号代码随想录来和上万录友一起打卡学习算法,来看看,你会发现相见恨晚!

如果感觉对你有帮助,不要吝啬给一个

「代码随想录」322. 零钱兑换 【动态规划】力扣详解!相关推荐

  1. LeetCode 322. 零钱兑换(动态规划)

    题目描述 给定不同面额的硬币 coins 和一个总金额 amount.编写一个函数来计算可以凑成总金额所需的最少的硬币个数.如果没有任何一种硬币组合能组成总金额,返回 -1. 示例 1: 输入: co ...

  2. 99. Leetcode 322. 零钱兑换 (动态规划-完全背包)

    步骤一.确定状态: 确定dp数组及下标含义 dp数组是个amout+1的数组,dp[j]表示的是装满容量为j的背包所需要的最 少物品的个数 步骤二.推断状态方程: 对于当前物品i, 有两种选择决定了d ...

  3. c++时间片轮转rr进程调度算法_「学习笔记」时间片轮转(RR)调度算法(详解版)...

    关键词:时间, 进程, 调度, 队列, 切换 时间片轮转(RR)时间片轮转(RR)调度算法是专门为分时系统设计的.它类似于 FCFS调度,但是增加了抢占以切换进程. 该算法中,将一个较小时间单... ...

  4. LeetCode刷题复盘笔记—一文搞懂完全背包之322. 零钱兑换问题(动态规划系列第十四篇)

    今日主要总结一下动态规划完全背包的一道题目,322. 零钱兑换 题目:322. 零钱兑换 Leetcode题目地址 题目描述: 给你一个整数数组 coins ,表示不同面额的硬币:以及一个整数 amo ...

  5. 动态规划:322. 零钱兑换(完整思路过程)

    题目 322. 零钱兑换 给你一个整数数组 coins,表示不同面额的硬币:以及一个整数 amount ,表示总金额. 计算并返回可以凑成总金额所需的 最少的硬币个数 .如果没有任何一种硬币组合能组成 ...

  6. 【必备算法】动态规划:LeetCode题(六)322. 零钱兑换,518. 零钱兑换 II

    322. 零钱兑换² 给定不同面额的硬币 coins 和一个总金额 amount.编写一个函数来计算可以凑成总金额所需的最少的硬币个数.如果没有任何一种硬币组合能组成总金额,返回 -1. 示例 1: ...

  7. LeetCode:322. 零钱兑换(python)

    LeetCode:322. 零钱兑换(python) 给定不同面额的硬币 coins 和一个总金额 amount.编写一个函数来计算可以凑成总金额所需的最少的硬币个数.如果没有任何一种硬币组合能组成总 ...

  8. golang力扣leetcode 322.零钱兑换

    322.零钱兑换 322.零钱兑换 题解 代码 322.零钱兑换 322.零钱兑换 题解 //state: dp[i]金额为i时所需最少硬币个数 //function: dp[i]=dp[i-n]+1 ...

  9. LeeCode 322. 零钱兑换

    322. 零钱兑换 难度中等709收藏分享切换为英文关注反馈 给定不同面额的硬币 coins 和一个总金额 amount.编写一个函数来计算可以凑成总金额所需的最少的硬币个数.如果没有任何一种硬币组合 ...

  10. [LeetCode] 322.零钱兑换 五种方法讲解

    322.零钱兑换 五种方法讲解 文章目录 322.零钱兑换 五种方法讲解 1 问题描述 2 问题分析 3 解决策略 3.1 递归-暴力解决 3.2 递归-加入存储 3.3 BFS 3.4 动态规划-自 ...

最新文章

  1. 2017计算机nit考试时间,关于2017年专接本NIT考试,你知道多少呢???
  2. c语言中eof_C语言的标准 “输入输出”!今天是你学C语言的第几天?
  3. 应用程序0xc0150002 错误
  4. Angular目录结构分析以及app.module.ts详解
  5. 面试准备系列01----面试中的链表题目汇总
  6. centos rpm 安装 perl_Linux【常用软件安装篇】
  7. web——Tomcat Maven插件及Servlet入门
  8. 新年彩蛋:Spring Boot自定义Banner
  9. 一幅漫画揭示了项目研发过程中存在的问题,太形象了
  10. yamlcpp遍历_gf-cli 命令行工具
  11. 组合枚举——妖梦拼木棒(洛谷 P3799)
  12. 蓝桥杯web开发-5道模拟题让你信心满满
  13. 百度优化排名_思路和步骤
  14. 内网通过代理服务器访问高德地图服务的方法
  15. 支持多线程的DRB server
  16. mysql多对多关系的理解,由一对多看向多对多
  17. Altium Designer生成Gerber文件的设置(嘉立创建议 )
  18. plc s7-200的a/d转换的c语言程序,200PLC 模拟量输入 A/D转换后的数字量不准-工业支持中心-西门子中国...
  19. 谷歌移动端seo优化如何做
  20. 高频交易是如何发展起来的?

热门文章

  1. 【BZOJ4837】LRU算法 [模拟]
  2. 文件系统[HDU-1413]
  3. 关于apache httpd.conf脚本的理解
  4. 【程序员的自我修养——链接、装载与库】笔记
  5. [转发]在Visual Studio 2010/2012/2013/2015上使用C#开发Android/IOS安装包和操作步骤
  6. Building Web Parts for Microsoft SharePoint Products and Technologies
  7. mysql5.7 主从数据库操作命令
  8. Monent.js:强大的日期处理类库
  9. B1231 [Usaco2008 Nov]mixup2 混乱的奶牛 状压dp
  10. CentOS 7.0yum安装MySQL