【算法题】322.零钱兑换-力扣(LeetCode)
1.题目
下方是力扣官方题目的地址
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
 
提示:
1 <= coins.length <= 121 <= coins[i] <= 231 - 10 <= amount <= 104
2.题解
这题和力扣官网的
509.斐波那契数
70. 爬楼梯
都差不多
在这题之前我们先来看看这两题
509.斐波那契数
斐波那契数 (通常用 F(n) 表示)形成的序列称为 斐波那契数列 。该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和。也就是:
F(0) = 0,F(1) = 1
F(n) = F(n - 1) + F(n - 2),其中 n > 1
 
给定 n ,请计算 F(n) 。
示例 1:
输入:n = 2
输出:1
解释:F(2) = F(1) + F(0) = 1 + 0 = 1
 
示例 2:
输入:n = 3
输出:2
解释:F(3) = F(2) + F(1) = 1 + 1 = 2
 
示例 3:
输入:n = 4
输出:3
解释:F(4) = F(3) + F(2) = 2 + 1 = 3
 
思路
斐波那契数列比较经典,我们知道它的递推式:
F(n) = F(n - 1) + F(n - 2),其中 n > 1
由此看来,F(n)的结果是与F(n-1)和F(n-2)有关的。
利用动态规划的思想,我们只需要将F(n-1)和F(n-2)的值存入一个数组中,用到时直接拿来用就是了
class Solution(object):
    def fib(self, n):
        """
        :type n: int
        :rtype: int
        """
        if n==0:return 0
        if n<=2:return 1
        dp=[0]*n
        dp[0],dp[1]=1,1
        for i in range(2,n):
            dp[i]=dp[i-1]+dp[i-2]
        return dp[-1]
 
70. 爬楼梯
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
示例 1:
输入:n = 2
输出:2
解释:有两种方法可以爬到楼顶。
1. 1 阶 + 1 阶
2. 2 阶
 
示例 2:
输入:n = 3
输出:3
解释:有三种方法可以爬到楼顶。
1. 1 阶 + 1 阶 + 1 阶
2. 1 阶 + 2 阶
3. 2 阶 + 1 阶
 
提示:
1 <= n <= 45
思路
本题完全可以类比斐波那契数列,我使用dp[i]表示爬到第i阶楼梯的方法,那么我们有两种方式爬到第i阶:
在dp[i-1]时爬1阶;
在dp[i–2]时爬两阶
所以很容易得出递推式:
dp[i]=dp[i-1]+dp[i-2]
class Solution(object):
    def climbStairs(self, n):
        """
        :type n: int
        :rtype: int
        """
        if n==1:return 1
        if n==2:return 2
        dp=[0]*(n+1)
        dp[1]=1
        dp[2]=2
        for i in range(3,n+1):
            dp[i]=dp[i-1]+dp[i-2]
        return dp[n]
 
类比前面两题,在来做本题322.零钱兑换,就显得非常轻松了
本题思路
我们设dp[i]表示当总金额为i时凑成总金额所需的 最少的硬币个数。
我们以coins = [1, 2, 5], amount = 11为例,我们知道,硬币就1,2,5这三种,所以当总金额为i时的最少硬币个数的得来就有三种情况:
dp[i-1]时再来拼凑面值1的硬币;
dp[i-2]时再来拼凑面值2的硬币;
dp[i-5]时再来拼凑面值5的硬币
如图所示:

所以就能得出递推式:
dp[i]=min(dp[i-coin]+1,dp[i])
coin代表的就是硬币的面值
我们将这题和爬楼梯做对比,发现:
我们的coins[1,2,5]就相当于爬楼梯中我们一次能爬的阶梯的阶数[1,2]
只不过爬楼梯是给定的[1,2],而本题在变化而已,写代码时,只要注意捕获coins的变化就行了
Python代码
class Solution(object):
    def coinChange(self, coins, amount):
        """
        :type coins: List[int]
        :type amount: int
        :rtype: int
        """
        dp=[float('inf')]*(amount+1)  # 初始化dp
        dp[0]=0
        for i in range(1,amount+1):
            for j in coins:           # j代表硬币的面值,由于coins的不确定性,所以得增加一个for来捕获coin(每个硬币的面值)
                if i-j>=0:            # 检验总额是否大于硬币面值
                    dp[i]=min(dp[i-j]+1,dp[i]) # 如果大于,才能就行递推
        return dp[-1] if dp[-1] != float('inf') else -1
 
3.结语
本人资历尚浅,发博客主要是记录与学习,欢迎大佬们批评指教!大家也可以在评论区多多交流,相互学习,共同成长。








![[邀请函]2024上海工博会,盟通邀您共享盛典!](https://img-blog.csdnimg.cn/img_convert/267899c9d9872affa725be5edf159071.png)







![[NSSCTF 2022 Spring Recruit]ezgame](https://i-blog.csdnimg.cn/direct/f1699c575391444290d30562d4886901.png)


