【经典算法】Leetcode-零钱兑换问题
一、题目
- 给你一个整数数组 coins ,表示不同面额的硬币;以及一个整数 amount ,表示总金额。
- 计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回 -1 。
- 你可以认为每种硬币的数量是无限的。
示例 1:
输入:coins = [1, 5, 11], amount = 15
输出:3
解释:11 = 5 + 5 + 5
二、思考
方法列举:
- 贪心:根据贪心法则,会先挑最大的,这样的话,会先选择10块的,然后选择1块的,选择过程是:10+1+1+1+1=15,这样显然不是本题的最优解。
- 动态规划:假设 F[i] 表示组成金额i所需的硬币数量,那么F[i] 可能有多种结果,按照题意,选择其中最小的一个结果输出即可。比如F[15]有三种不同的兑换方法(兑换次数分别为5、3、5),最终输出3即可。
三、动态规划解法
采用以上动态规划的思路,可以将以上过程拆成2个步骤:
- 计算第一次挑选每个硬币coin,对应的F[i]:F[i] = F[i - coin] + 1
- 及时更新最小值: F[i] = min(F[i], F[i - coin] + 1)
Python代码:
class Solution:
def coinChange(self, coins: List[int], amount: int) -> int:
dp = [inf] * (amount + 1) # 定义dp[i]表示,组成金额i所需的最少硬币数量
dp[0] = 0
for coin in coins: # 计算逐个硬币下的dp[i]
for i in range(coin, amount + 1):
dp[i] = min(dp[i], dp[i - coin] + 1) # 在计算过程中,还实时比较得到最小的f[i]
return dp[amount] if dp[amount] != inf else -1
Ref:
- Leetcode: https://leetcode.cn/problems/coin-change/?envType=study-plan-v2&envId=top-100-liked