--- 找零兑换问题 --- 作为店家,找零:最少纸币/硬币数 1. 贪心策略 若硬币体系为:[25,21,10,1],找零63,则贪心策略失效 2. 递归 大量重复计算,极低效 3. 动态规划
1. 贪心策略
def change_greedy(t, n):
"""贪心策略"""
m = [0 for _ in range(len(t))]
for i, money in enumerate(t):
m[i] = n // money
n = n % money
return f'找零: {m},剩余 {n} 元找不开'
2. 递归
def change_recursion1(t, n):
"""递归"""
min_coin = n
# 递归基本结束条件
if n in t:
return 1
else:
for i in [c for c in t if c <= n]:
# 递归,减小规模:每次减去一种面值,挑选最小数量
num = 1 + change_recursion1(t, n - i)
if num < min_coin:
min_coin = num
return min_coin
def change_recursion2(t, n):
"""递归 (改进版)"""
# 记录最优解
known = [0] * (n + 1)
min_coin = n
if n in t:
known[n] = 1
return 1
# 查表成功,直接用最优解
elif known[n] > 0:
return known[n]
else:
for i in [c for c in t if c <= n]:
num = 1 + change_recursion1(t, n - i)
if num < min_coin:
min_coin = num
# 找到最优解,记录到表中
known[n] = min_coin
return min_coin
3. 动态规划
def change_dp(t, n):
"""动态规划"""
# dp 记录每一步的最优解、trace 记录硬币组合
dp = [0] * (n + 1)
trace = [0] * (n + 1)
# 从 1 到 n 逐个计算最少硬币数
for money in range(1, n + 1):
# 初始化一个最大值
count = money
# 初始化新硬币
new_coin = 1
# 减去每个面值,查找剩余数量的最优解,记录总的最少数
for j in [c for c in t if c <= money]:
if dp[money - j] + 1 < count:
count = dp[money - j] + 1
new_coin = j
# 记录当前钱数的最优解,记录到表中
dp[money] = count
trace[money] = new_coin
return dp[n], trace
def change_dp_traceback(t, n):
dp, trace = change_dp(t, n)
coin = n
while coin > 0:
curr = trace[coin]
print(curr)
coin -= curr