class Solution:
def coinChange(self, coins: List[int], amount: int) -> int:
dp =[inf]*(amount+1) #包含 0 和 amount 在内,一共有 amount - 0 + 1 = amount + 1 个不同的金额值需要存储结果。
dp[0]=0 #dp[0] = 0 是一个确定的初始条件(凑成金额 0 需要 0 个硬币),它不需要是 inf,并且必须显式设置为 0 作为动态规划的起点。
for i in range(1, amount+1):#外层循环遍历所有我们想要计算的金额,从 1 到 amount
for j in coins:#内层循环遍历所有可用的硬币面额 j,如果通过其他的硬币 j' 找到了另一种凑成 i 的方法 (dp[i-j'] + 1)
if i>=j:#确保我们当前考虑的金额 i 必须大于或等于硬币面额 j,否则我们不可能通过加上一个面额为 j 的硬币来凑成金额 i
#比较 “当前已经找到的凑成 i 的最少硬币数 (dp[i])” 和 “通过使用硬币 j 凑成 i 所需的硬币数 (dp[i-j]+1)”,然后取两者中较小的那一个,作为更新后的 dp[i] 的值。这样就能确保 dp[i] 始终保存着凑成金额 i 的 最少 硬币数。dp[i] (在 min 函数的第一个参数位置): 这个代表在考虑使用硬币 j 之前,我们已经找到的凑成金额 i 的最少硬币数。在内层循环开始处理金额 i 时,dp[i] 的初始值是 inf(无穷大),表示暂时还没有找到任何方法凑成金额 i。随着内层循环遍历不同的硬币 j,dp[i] 会被更新为当前找到的最小值。
dp[i] = min(dp[i],dp[i-j]+1)
return dp[-1] if dp[-1]!=inf else -1
class Solution:
def coinChange0(self, coins: List[int], amount: int) -> int:
dp =[inf]*(amount+1) #包含 0 和 amount 在内,一共有 amount - 0 + 1 = amount + 1 个不同的金额值需要存储结果。
dp[0]=0 #dp[0] = 0 是一个确定的初始条件(凑成金额 0 需要 0 个硬币),它不需要是 inf,并且必须显式设置为 0 作为动态规划的起点。
for i in range(1, amount+1):#外层循环遍历所有我们想要计算的金额,从 1 到 amount
for j in coins:#内层循环遍历所有可用的硬币面额 j,如果通过其他的硬币 j' 找到了另一种凑成 i 的方法 (dp[i-j'] + 1)
if i>=j:#确保我们当前考虑的金额 i 必须大于或等于硬币面额 j,否则我们不可能通过加上一个面额为 j 的硬币来凑成金额 i
#比较 “当前已经找到的凑成 i 的最少硬币数 (dp[i])” 和 “通过使用硬币 j 凑成 i 所需的硬币数 (dp[i-j]+1)”,然后取两者中较小的那一个,作为更新后的 dp[i] 的值。这样就能确保 dp[i] 始终保存着凑成金额 i 的 最少 硬币数。dp[i] (在 min 函数的第一个参数位置): 这个代表在考虑使用硬币 j 之前,我们已经找到的凑成金额 i 的最少硬币数。在内层循环开始处理金额 i 时,dp[i] 的初始值是 inf(无穷大),表示暂时还没有找到任何方法凑成金额 i。随着内层循环遍历不同的硬币 j,dp[i] 会被更新为当前找到的最小值。
dp[i] = min(dp[i],dp[i-j]+1)
return dp[-1] if dp[-1]!=inf else -1
#recurison 自上而下的方法
def coinChange1(self, coins: List[int], amount: int) -> int:
memo=[-1]*(amount+1)
def solve(target):
if target ==0:
return 0
if target<0: #代表着当前这条递归探索路径是无效或不可能的。
return inf
if memo[target] !=-1:#我们之前是不是已经计算过凑成金额 target 最少需要多少硬币了?if 是。那么这行代码就直接从备忘录 memo 中取出之前存好的结果,并将其返回给上一层调用 solve 的地方。
return memo[target]
min_needed =inf
for coin in coins:
#递归调用,解决子问题, 凑够target-coin 需要的最少硬币
sub_result =solve(target-coin)
#如果子问题有解, 不是无穷大 对应上面 if target<0 的情况
if sub_result !=inf :
#更新当前target 最小硬币组合 子问题的解+当前的coin这枚硬币
min_needed =min(min_needed,sub_result+1)
memo[target]=min_needed
return min_needed
result =solve(amount)
return result if result !=inf else -1
#recurison 的递归,调用 lru_cache缓存方法,自动实现备忘录功能
def coinChange(self, coins: List[int], amount: int) -> int:
# 使用 lru_cache 自动实现备忘录功能
@functools.lru_cache(maxsize =None)
def sovle(target):
if target ==0:
return 0
if target <0:
return inf
min_needed=inf
for coin in coins:
sub_result=sovle(target-coin)
if sub_result !=inf :
min_needed=min(min_needed,sub_result+1)
return min_needed
# ---- 主函数逻辑 ----
result = sovle(amount)
return result if result != float('inf') else -1