问题描述:
给你一个整数数组 coins
,表示不同面额的硬币;以及一个整数 amount
,表示总金额。
计算并返回可以凑成总金额所需的 最少的硬币个数
。如果没有任何一种硬币组合能组成总金额,返回-1
。
注意:你可以认为每种硬币的数量是无限的。
示例 1:
输入:coins = [1, 2, 5], amount = 11
输出:3
解释:11 = 5 + 5 + 1
示例 2:
输入:coins = [2], amount = 3
输出:-1
提示:
1 <= coins.length <= 12
1 <= coins[i] <= 2^31 - 1
0 <= amount <= 10^4
问题分析:
标准的动态规划题目,本题的 最少的硬币个数
,其实是0 1
背包问题,思想一致。现在看看解法:
(1)设dp[i]
表示总金额为 i
时需要的最少硬币数,很显然 dp[i] = min(dp[i], dp[i - coin] + 1)
,其中coin
表示coins
中所有硬币种类的中的一种,后面+1
很显然是:上一个状态加上当前硬币
,循环所有种硬币
即可。
(2)dp
的初始化需要特别注意,一般求最小值要初始化无穷大float('inf')
,最后是dp[0]
,很显然dp[0]=0
,因为总金额为0
的时候,就不用兑换
了。
Python3实现:
# @Time :2023/09/07
# @Author :Liu
# 动态规划
class Solution:
def coinChange(self, coins: List[int], amount: int) -> int:
dp = [float('inf')] * (amount + 1)
dp[0] = 0
for i in range(1, amount+1):
for coin in coins:
if i >= coin: # 添加一个限制条件
dp[i] = min(dp[i], dp[i - coin] + 1)
return dp[-1] if dp[-1] != float('inf') else -1
举一反三
就这个题目而言,如果说求的是有多少种组合数那?类似的题目:
- 算法题 - 拼凑面额 - Python
- LeetCode 39. 组合总和 : 返回
所有的组合
,注意:数组里的数字可以重复使用
。排序 + 深度优先即可。 - LeetCode 40. 组合总和 II:返回
所有的组合
,注意:数组里的数字只能用1次
。排序 + 深度优先即可。 - LeetCode 377. 组合总和 Ⅳ:返回
所有的组合数
,注意:数组里的数字不同,且可以重复使用
。其实是LeetCode 39. 组合总和
的缩小版,用动规求解。
class Solution:
def combinationSum4(self, nums: List[int], target: int) -> int:
dp = [1] + [0] * target
for i in range(1, target + 1):
for num in nums:
if num <= i:
dp[i] += dp[i - num]
return dp[target]
相关参考:LeetCode:322. 零钱兑换
声明: 总结学习,有问题或不当之处,可以批评指正哦,谢谢。