零钱兑换 动态规划

322. 零钱兑换

给你一个整数数组 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
posted @   JunanP  阅读(11)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示