Leetcode 322 零钱兑换 用动态规划解决 python3

题目要求:给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。
示例 1:
输入: coins = [1, 2, 5], amount = 11
输出: 3
解释: 11 = 5 + 5 + 1
示例 2:
输入: coins = [2], amount = 3
输出: -1
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/coin-change

=======================================================================
看了好久官方这个解法 还是很懵 作为小白的我 打算写一下 来捋捋思路

=======================================================================
通过动态规划方法进行解决,首先定义一个函数 F(i) , 其中i代表要组成的最终金额所需最少的硬币数量
动态规划的关键是状态转移 那么我们来思考 F(i)的 前一个状态应该是什么呢?
因此可以想到 在一个未知的状态下 我们拿到了一枚硬币(此时暂不考虑硬币的金额) 这时达到了组成最终金额所需的最少硬币数量。而这个未知状态也需保证组成其金额的硬币数量最少。可以得到如下状态转移方程。
状态转移方程
其中cj 代表的是达到最终状态取到硬币的面值

这个时候我们已经得到了状态转移公式:比如最终金额为11,那我们看看前一步是什么呢?

F(11)= min(F(11-1),F(11-2),F(11-5)) +1
F(11)=min(F(10),F(9),F(6))+1

那么F(10) 、F(9)、F(6) 是需要求得的 (以F(10)为例进一步计算)

F(10) =min(F(10-1),F(10-2),F(10-5)) +1
F(10)=min(F(9),F(8),F(5))+1

看到这里我们似乎发现了要想求取F(11),那么我们需要知道F(0)、F(1)、F(2) …F(9)、F(10)到所有值,F(0)表示最终金额为0是不需要取硬币的
注意: F(0)是动态规划的边界值

因此可以自底向上将每一个F(i)计算出来,采用动态规划算法算出最终结果。
仔细观察这个状态转移方程可以看出,i和cj都是变化的,所以采用双重for循环可以计算。

第一个for循环就是硬币的面值变换:比如 1 、2、 5
第二个for循环就是i的变化

通过这两个循环就可以获取每一个F(i)的最小值然后可以用类似于备忘录的思想,把所有的F(i)的值用列表储存下来。
思考: 此处的备忘录列表的长度是多少呢? 根据上面提到的例子 如果i的值为11
我们需要储存F(0-11)的值也就是12(amount + 1)个数据
具体的程序代码及注释如下
Leetcode 322 零钱兑换 用动态规划解决 python3_第1张图片
复杂度分析

时间复杂度:对于每个状态,每次需要枚举 n 个面额来转移状态,所以一共需要 O(Sn)O 的时间复杂度。
空间复杂度:O(S)。DP 数组需要开长度为总金额 S 的空间。

你可能感兴趣的:(算法,Leetcode,python,动态规划,leetcode,算法)