零钱兑换问题——python动态规划解法

问题:

给定不同面额的硬币(coins)和一个总金额(amount)。写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合方式能组成总金额,返回-1

示例 1:
coins = [1, 2, 5], amount = 11
return 3 (11 = 5 + 5 + 1)

示例 2:
coins = [2], amount = 3
return -1.

注意:

你可以认为每种硬币的数量是无限的。(此题目摘自leetcode)

什么是动态规划?其思路是为了求解当前的问题的最优解,使用子问题的最优解,然后综合处理,最终得到原问题的最优解。网上有很多介绍的文章,但是对于初学者(比如我)来说,看起来会有些懵。我个人的理解是,当总金额为amount时,所需的最少硬币个数为dp[amount],那么当amount = 11时,求出所有dp[1]、dp[2]、...、dp[11]的值。dp[1]到dp[10]就可以说是dp[11]的子问题,需要通过他们来求最终解。

以示例1为例,我们需要尽可能少的硬币个数,所以从11的总金额中取出任意一枚硬币,剩下的金额所需最少硬币个数再加上1就是所需硬币个数,即所需硬币个数为:dp[10]+1、dp[9]+1、dp[6]+1,再从中取最小值,即可求解。以此类推,dp[10]=min(dp[9]+1,dp[8]+1,dp[5]+1)...所以可以看出,通过求出所有dp[1]、dp[2]、...、dp[10]的值,最终就能得到dp[11]的值。

以下是代码实现:

def coinChange(coins, amount):
"""
:type coins: List[int]
:type amount: int
:rtype: int
"""
coins.sort() #给硬币从小到大排序
dp = {0:0} #生成字典dp,并且当总金额为0时,最少硬币个数为0
for i in range(1,amount + 1):
dp[i] = amount + 1 #因为硬币个数不可能大于amount,所以赋值amount + 1便于比较
for j in coins:
if j <= i:
dp[i]=min(dp[i],dp[i-j]+1)
#for i in range(1,amount + 1):
#print('dp[%d]:'%(i), dp[i])
if dp[amount] == amount + 1: #当最小硬币个数为初始值时,代表不存在硬币组合能构成此金额
return -1
else:

return dp[amount]

一开始不太理解,为什么要求金额11的解需要算出1-10的所有解,这样不是把问题弄得更复杂了吗?后来醒悟是思路问题,这有些递归的思想在里边,就像盖楼一样,你不可能不用1-10层就只盖个11层。之所以写这篇文章,是因为想保留我现在作为初学者的视角,等以后学习更深入些再回过头来说不定会有新的感悟,望大佬轻喷

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值