LeetCode 322. Coin Change(Python):深入理解动态规划和备忘录
2024-02-05 19:20:28
- LeetCode 322. Coin Change 题意简介
LeetCode 322. Coin Change(Python)是LeetCode题库中一道经典的动态规划问题。题目如下:
给定一种硬币,它的面额为c1,c2,...,cn,你需要用这些硬币凑出金额为amount的零钱。求出凑出这个金额的硬币组合数的最小值。如果 невозможно凑出金额amount,则返回-1。
比如,给定硬币的面额为[1,2,5]和amount=11,则可以凑出金额11的硬币组合为[5,5,1]和[2,2,2,2,2,1]。最小组合数为2,所以返回2。
2. 动态规划算法的应用
本题的求解可以使用动态规划算法。动态规划算法是一种自底向上的求解方法,它将问题的解空间划分为若干个子问题,然后逐个求解这些子问题,最终得到整个问题的解。
对于本题,我们可以定义一个二维数组dp,其中dp[i][j]表示使用前i个硬币凑出金额j所需的最小硬币数量。显然,dp[i][j]可以由dp[i-1][j]和dp[i][j-c_i]转移而来,即:
dp[i][j] = min(dp[i-1][j], dp[i][j-c_i] + 1)
其中,c_i表示第i个硬币的面额。
3. 备忘录的应用
为了避免重复计算,我们可以使用备忘录来记录已经计算过的子问题的解。这样,当我们再次遇到相同的子问题时,可以直接从备忘录中取出结果,而无需重新计算。
在LeetCode 322. Coin Change(Python)中,我们可以使用一个字典作为备忘录。字典的键是子问题的状态,即(i, j),字典的值是子问题的解,即dp[i][j]。
4. 算法实现
接下来,我们给出本题的Python代码实现:
def coin_change(coins, amount):
"""
:type coins: List[int]
:type amount: int
:rtype: int
"""
# 初始化备忘录
memo = {}
def dp(i, j):
"""
:type i: int
:type j: int
:rtype: int
"""
# 已经计算过子问题的解,直接从备忘录中取出
if (i, j) in memo:
return memo[(i, j)]
# 递归终止条件
if j == 0:
return 0
# 超出硬币数组的范围
if i < 0:
return -1
# 硬币面额大于剩余金额
if coins[i] > j:
return dp(i - 1, j)
# 当前硬币面额小于剩余金额
# 可以选择使用当前硬币或者不使用当前硬币
result = min(dp(i - 1, j), dp(i, j - coins[i]) + 1)
# 将子问题的解放入备忘录
memo[(i, j)] = result
return result
# 调用函数计算最终结果
result = dp(len(coins) - 1, amount)
# 不存在解
if result == -1:
return -1
# 返回最少的硬币数量
return result
5. 时间复杂度分析
使用动态规划和备忘录求解LeetCode 322. Coin Change(Python)的时间复杂度为O(n*amount),其中n是硬币的数量,amount是目标金额。
6. 练习题
为了巩固所学知识,您可以尝试以下练习题:
- 给定一种硬币,它的面额为c1,c2,...,cn,你需要用这些硬币凑出金额为amount的零钱。求出凑出这个金额的硬币组合数的最大值。如果 невозможно凑出金额amount,则返回-1。
- 给定一种硬币,它的面额为c1,c2,...,cn,你需要用这些硬币凑出金额为amount的零钱。求出凑出这个金额的硬币组合数的所有可能情况。
- 给定一种硬币,它的面额为c1,c2,...,cn,你需要用这些硬币凑出金额为amount的零钱。求出凑出这个金额的硬币组合数的所有可能情况,并且每种组合中硬币的个数不超过k个。
7. 总结
LeetCode 322. Coin Change(Python)是一道经典的动态规划问题,通过这道题,我们深入理解了动态规划算法的思想和备忘录的应用。此外,我们还提供了多种练习题,帮助您巩固所学知识。希望本文能够对您的学习有所帮助。