零钱兑换 动态规划
给你一个整数数组 coins ,表示不同面额的硬币;以及一个整数 amount ,表示总金额。
计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回 -1 。
你可以认为每种硬币的数量是无限的。
示例 1:
输入:coins = [1, 2, 5], amount = 11
输出:3
解释:11 = 5 + 5 + 1
示例 2:
输入:coins = [2], amount = 3
输出:-1
示例 3:
输入:coins = [1], amount = 0
输出:0
思路:
这道题是标准的动态规划问题。我们定义一个dp数组,dp[n]就表示总成总金额为n所需的硬币数。
明确了dp数组的定义后,我们下一步要考虑状态转移方程如何写。其实做过这么多dp问题之后,基本思路应该是会有了:自底向上去生成dp,dp[i]来自于dp[i-硬币面值]+1。只要有了这么一个“雏形”,接下来就是完善的问题了。
题目中我们要求最少硬币数,而硬币面值会有多种,因此我们状态转移方程中,要用min()来不断选择最小的dp[i-coin]+1,并且因为使用min方法,我们初始化dp数组时得用极大值float('inf'),而不是以前常用的0。
因为硬币的种类是随入参而改变的,所以我们并不知道具体的coin是什么,因此我们从小到大生成dp时,要遍历coins并进行判断:如果i-coin小于0,说明此时硬币太大,不需要,跳过;如果i-coin等于0,说明只需要这1个硬币就好,dp[i]=1;如果i-coin大于0,此时就需要进入我们的状态转移,尝试通过dp[i-coin]来得到dp[i]。(如果连dp[i-coin]也不曾有解(还是无穷),那么dp[i]也就无解了(也是无穷))
所以,当我们的dp遍历结束后,如果我们的dp[amount]不是一个常数(即还是无穷),说明我们找不到任何一种硬币组合能够成总金额,返回的时候根据题意将其处理为-1即可。
代码:
class Solution(object):
def coinChange(self, coins, amount):
dp =[float('inf')]*(amount+1)#因为后面要用min来更新,所以初始化得用最大值
#dp[n]表示构成总金额为n所需的硬币个数
dp[0]=0#构成总金额为0,自然需要0个硬币
for i in range(1,amount+1):#构成总金额为1到amount,通过dp迭代实现
for coin in coins:
if i-coin<0:#这个硬币太大了,用不着
continue
elif i -coin==0:#这个硬币正好够用
dp[i]=1 #此时只需要1个硬币即可
elif i-coin>0:#这个硬币可以用来作一部分
#遍历不同种硬币,找到最小数值
dp[i]=min(dp[i],dp[i-coin]+1)
#下面这个写法的意思是,如果dp[amount]不是无穷,就直接返回;否则返回-1
return dp[amount] if dp[amount]!=float('inf') else -1
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了