🚀 优质资源分享 🚀
学习路线指引(点击解锁) | 知识定位 | 人群定位 |
---|---|---|
🧡 Python实战微信订餐小程序 🧡 | 进阶级 | 本课程是python flask+微信小程序的完美结合,从项目搭建到腾讯云部署上线,打造一个全栈订餐系统。 |
💛Python量化交易实战💛 | 入门级 | 手把手带你打造一个易扩展、更安全、效率更高的量化交易系统 |
深入浅出零钱兑换问题——背包问题的套壳
前言
在本篇文章当中主要通过介绍两个算法题,从最基本的问题开始深入浅出零钱兑换问题,帮助大家从动态规划的本源深入理解问题当中的原理,并且学会自己分析问题,分析数据之间的依赖关系,通过分析这种关系自己推导算法的优化过程,再也不怕类似于背包问题的算法题了。
零钱兑换
题目
给你一个整数数组 coins ,表示不同面额的硬币;以及一个整数 amount ,表示总金额。
计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回 -1 。
你可以认为每种硬币的数量是无限的。
示例
示例1
| | 输入:coins = [1, 2, 5], amount = 11 |
| | 输出:3 |
| | 解释:11 = 5 + 5 + 1 |
示例2
| | 输入:coins = [2], amount = 3 |
| | 输出:-1 |
状态表示和状态转移方程
在求解动态规划问题的时候通常的步骤有以下几个:
- 寻找能够表示状态的数组
dp
,即我们需要寻找dp
的含义,分析需要用几纬数组表示具体的状态。 - 通过分析问题,寻找动态转移公式。
- 初始化状态数组。
- 通过分析动态转移方程,确定数组的遍历顺序。
状态表示数组
在背包问题当中通常都是用一个二维数组表示数据的状态,在这个问题当中我们使用一个二维数组dp
表示我们需要的状态:
dp[i][j]
表示使用coins
前i
种面额的硬币表示金额等于j
时使用的最少的金币,那么我们最终答案就是dp[N][amount]
,他表示使用coins
数组当中所有面额的硬币表示amount
需要的最少的硬币个数。
寻找动态转移方程
在确定了状态表示的数组之后,现在我们就需要分析出动态转移方程了,在这个问题当中对于每一种面额的硬币我们都有两种选择:选和不选,但是在这个问题当中题目已经说明了对于每一种货币都可以认为是无限的,如果我们不选择,那这种情况比较简单,但是如果选择了这种情况就比较复杂了:
- 不选,这种情况比较简单,比如对于
dp[i][j]
,如果第i
种面额的货币不选择,那么说明只使用前i - 1
种面额的货币,那么dp[i][j] = dp[i - 1][j]
,也就是说明如果使用前i