给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。
示例 1:
输入: coins = [1, 2, 5], amount = 11
输出: 3
解释: 11 = 5 + 5 + 1
示例 2:
输入: coins = [2], amount = 3
输出: -1
说明:你可以认为每种硬币的数量是无限的。
题目连接:https://leetcode-cn.com/problems/coin-change/
方法一:递归实现
思路:见到可以将大问题划分为更小规模的问题,那么就可以想到用动态规划的方法。就像这道题,首先我们知道amount规模的问题,可以变成amount-coins[i]规模的问题,那么问题来了,amount规模的问题与amount-coins[i]规模的问题之间的关系是什么,递归结束条件是什么(也就是说已知的边界值是什么?)?然后将这个思路写成递归方程和递归结束条件,之后将其转换成代码。由于递归会超时,所以要用字典保存计算的中间结果。
注意:如果amount-coins[i]<0时,不符合题意,所以需要判断一下满足amount>=coins[i]才能递归。
class Solution:
def coinC(self, amount):
if amount==0:
return 0
tt = float('Inf')
for i in range(len(self.coins)):
if amount>=self.coins[i]:
if self.amt[amount-self.coins[i]]==-1:
aa=1+self.coinC(amount-self.coins[i])
else:
aa = 1 + self.amt[amount - self.coins[i]]
tt = min(tt, aa)
self.amt[amount]=tt
return tt
def coinChange(self, coins, amount):
self.coins = coins
# self.tt = float('Inf')
self.amt = [-1 for i in range(amount+1)]
ans = self.coinC(amount)
if ans!=float('Inf'):
print(ans)
else:
print(-1)
coins = [1, 2, 5]
amount = 11
s = Solution()
s.coinChange(coins, amount)
方法二:动态规划
思路:从前向后想,假设我有初始最优解,那么,我怎么求更大规模的最优解。就这一道题来说,当amount==0时,我最少需要找0个硬币,那更大规模的呢?怎么求解呢?如果是amount==1时,如果存在1元硬币,那么就返回1,否则,是无穷大,也就是没办法找;如果amount==2时,可以是因为amount>1,所以可以是1+f(2-1)=1+1=2,如果存在两元硬币的话,就是1+f(2-2)=1+0=1,将这两种方案比较,看哪个硬币个数少就要哪个,最后计算到amount==题目中所给的金额,即为所求。
dp[0]=0
dp[i]=1+min{dp[i-coins[j]]}(j=0, ..., len(coins)-1)
注意:这个也是只有i>=coins[j]时才更新
class Solution:
def coinChange(self, coins, amount):
dp=[float('Inf') for i in range(amount+1)]
dp[0]=0
for i in range(1, amount+1):
tt = float('Inf')
for j in range(len(coins)):
if i>=coins[j]:
a = dp[i-coins[j]]
tt = min(tt, a)
dp[i]=tt+1
if dp[amount]==float('Inf'):
return -1
else:
return dp[amount]
动态规划入门第一题,加油!!!