题目:
给你一个整数数组 coins ,表示不同面额的硬币;以及一个整数 amount ,表示总金额。
计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回 -1 。
你可以认为每种硬币的数量是无限的。
示例:
输入:coins = [1, 2, 5], amount = 11
输出:3
解释:11 = 5 + 5 + 1
思路:
动态规划
建立一个长度为amount+1的动态数组,其中dp[i]表示要组成i块钱,需要的最少硬币数,先初始化每个位置上硬币数为正无穷,然后初始化索引0位置硬币数为0,然后遍历动态数组,dp[amount]表示的就是要组成amount块钱,需要的最少硬币数,对于每个位置上,遍历可选择零钱的整数数组。
如果遍历到的零钱数额小于或者等于要组成的总数,才可以考虑是不是往里放。
- 如果这个硬币不拿,那当前位置需要的硬币数就还是原来的,
- 如果拿这个硬币,当前位置需要的硬币数就是总数减去当前遍历的硬币数额后对应位置上的零钱数再加上1,在拿或者不拿之间选择更小的硬币数。
- 最后如果动态数组最后一位上不是正无穷,说明现有的零钱可以组成整数,返回最后一个位置的零钱数,否则返回-1。
注:
这个题目和279完全平方数问题的区别在于,完全平方数问题中我们可以构造全部小于和n的数构成的数组,这样就可以外层循环遍历可选择的数,内层循环遍历对应的位置,不用进行额外的判断,本问题中可选择的硬币数额是给定的,要判断其是否小于要组成的和,所以这里是外层循环遍历位置,内层循环遍历可选择的数。
class Solution(object):
def coinChange(self, coins, amount):
"""
:type coins: List[int]
:type amount: int
:rtype: int
"""
dp = [float('inf')] * (amount+1)
dp[0] = 0
for i in range(1,amount + 1):
for coin in coins:
if i-coin >= 0:
dp[i] = min(dp[i],dp[i-coin]+1)
return dp[-1] if dp[-1] != float('inf') else -1
# 常规操作,先遍历可选数组,再遍历动态数组的不同索引位置,可
for coin in coins:
for i in range(coin,amount+1):
dp[i] = min(dp[i],dp[i-coin]+1)
return dp[-1] if dp[-1] != float('inf') else -1