给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1
。
示例 1:
输入: coins =[1, 2, 5]
, amount =11
输出:3
解释: 11 = 5 + 5 + 1
示例 2:
输入: coins =[2]
, amount =3
输出: -1
说明:
你可以认为每种硬币的数量是无限的。
简单介绍一下背包问题:
背包问题
1. 01背包,选和不选的问题
2. 完全背包,选几个的问题(物品不限次数)->转化成背包问题解决(每次选还是不选,重复访问同一物品)
3. 多重背包,即每个物品有限个
思路1:动态规划
状态转移方程:
状态:记录0-amount内,每种金额所需的最少硬币数
f[amount]=min(f[amount],f[amount-coints[i]+1]) #f[amount-coints[i] 表示选取一个coin后,还剩的待凑的钱数
class Solution(object):
def coinChange(self, coins, amount):
"""
:type coins: List[int]
:type amount: int
:rtype: int
"""
# 1. 动态规划
# 记录0-amount内,每种金额所需的最少硬币数
# f[amount]=min(f[amount],f[amount-coints[i]]+1)
dp=[float('inf')]*(amount+1)
dp[0]=0
for i in range(amount+1):
for j in coins:
if i>=j:
dp[i]=min(dp[i],dp[i-j]+1)
if dp[-1]>amount:return -1
else: return dp[-1]
法二:DFS
先将硬币面额按照大小排序,从每个不同面额的硬币开始DFS
class Solution(object):
def coinChange(self, coins, amount):
"""
:type coins: List[int]
:type amount: int
:rtype: int
"""
# dfs(实质是可以重复访问的dfs过程) 优先选大面额的
self.res=amount+1
coins_len=len(coins)
if coins_len==0:return -1
if amount==0:return 0
coins.sort(reverse=True)
if amount<coins[-1]:return -1
count=0
# 从每个面额开始深搜
for i in range(coins_len):
self.dfs(coins,i,amount,count)
if self.res!=amount+1:return self.res
else:return -1
def dfs(self,coins,coins_index,amount,count):
# dfs过程
if amount==0:
self.res=min(self.res,count)
return
for i in range(coins_index,len(coins)):
# 继续dfs条件
if coins[i]<=amount<(self.res-count)*coins[i]:
self.dfs(coins,i,amount-coins[i],count+1)