📜  硬币变化 | DP-7(1)

📅  最后修改于: 2023-12-03 15:11:24.032000             🧑  作者: Mango

硬币变化

硬币变化问题是一个经典的动态规划问题,目标是确定给定面额硬币的组合方式,使其总价值恰好等于给定值。

问题描述

给定一组面值为 $coins$ 的硬币和一个目标值 $amount$,编写一个函数来计算可以用给定的硬币组成的面值总和是否等于 $amount$。可以假设每个硬币都可以无限次被使用。

示例

输入:$coins = [1, 2, 5], amount = 11$

输出:3 (使用 $5, 5, 1$ 硬币)

解题思路

这是一个典型的动态规划问题,需要用到动态规划的思想和技巧:

  1. 确定状态:设 $dp[i]$ 为凑出面值 $i$ 所需的最小硬币数,初始化为 $dp[0]=0$,其他值初始化为一个特殊的值,比如 -1 或正无穷。

  2. 状态转移:对于每个面值 $i$,需要遍历每一种硬币 $coins_j$,找到凑出 $i-coins_j$ 的最小硬币数,并将其加上 1,即可得到 $dp[i]$ 的值。注意需要判断 $i-coins_j$ 是否越界。

  3. 返回结果:如果 $dp[amount]$ 的值不为特殊值,说明可以用给定的硬币组合成 $amount$ 的面值,返回其值;否则返回 -1。

代码
def coinChange(coins, amount):
    dp = [float('inf')] * (amount + 1)
    dp[0] = 0
    for i in range(1, amount + 1):
        for j in range(len(coins)):
            if coins[j] <= i:
                dp[i] = min(dp[i], dp[i - coins[j]] + 1)
    return dp[amount] if dp[amount] != float('inf') else -1
时间复杂度

本算法的时间复杂度为 $O(N^2)$,其中 $N$ 是目标值 $amount$ 的大小。算法的主要时间耗费在双重循环中,而循环次数最多为 $amount$ 的平方。

空间复杂度

本算法的空间复杂度为 $O(N)$,用一个长度为 $N+1$ 的数组存储了所有状态矩阵。