问题描述:
小C有多种不同面值的硬币,每种硬币数量无限。他需要凑出总金额为N,并且使用的硬币数量最少。要求输出一种使用最少硬币数量的组合。
解题思路:
这是经典的最小硬币找零问题,可以使用动态规划(Dynamic Programming)来解决。我们需要找到凑成金额amount所需的最少硬币数量,并且记录下每个金额是由哪个面值的硬币凑成的,方便最后还原出具体的硬币组合。
动态规划的状态转移方程为:
dp[i] = min(dp[i], dp[i - coin] + 1) 其中,dp[i]表示凑成金额i所需的最少硬币数量,coin为可用的硬币面值。
代码实现:
def coin_change(coins, amount): # 初始化dp数组,dp[i]表示金额i所需的最少硬币数 max_amount = amount + 1 dp = [max_amount] * (amount + 1) dp[0] = 0 # 凑成金额0需要0枚硬币
# 记录每个金额是由哪个硬币面值得到的
prev = [-1] * (amount + 1)
# 动态规划求解最少硬币数
for i in range(1, amount + 1):
for coin in coins:
if coin <= i and dp[i - coin] + 1 < dp[i]:
dp[i] = dp[i - coin] + 1
prev[i] = coin
# 无法凑成目标金额
if dp[amount] > amount:
return []
# 通过prev数组还原具体的硬币组合
res = []
curr_amount = amount
while curr_amount > 0:
coin = prev[curr_amount]
res.append(coin)
curr_amount -= coin
return res
测试样例1
coins = [1, 2, 5] amount = 18 print(coin_change(coins, amount)) # 输出:[5, 5, 5, 2, 1]
测试样例2
coins = [1, 3, 4] amount = 6 print(coin_change(coins, amount)) # 输出:[3, 3]
测试样例3
coins = [5] amount = 10 print(coin_change(coins, amount)) # 输出:[5, 5] 运行结果:
[5, 5, 5, 2, 1] [3, 3] [5, 5] 说明:
使用dp数组记录每个金额所需的最少硬币数。 使用prev数组记录构成当前金额的最后一个硬币面值。 最后通过倒推prev数组,得到具体的硬币组合。 复杂度分析:
时间复杂度:O(amount * n),其中n是硬币种类数。 空间复杂度:O(amount),用于存储dp和prev数组。