硬币变化递归算法展开
Coin change recursive algorithm unwinding
我正在尝试 unwind
此 algorithm
中的 recursive
函数。硬币找零问题:给定目标数量 n 和一个包含不同硬币价值的列表 array
,要达到找零数量所需的最少硬币是多少。
def rec_coin(target,coins):
# Default to target value
min_coins = target
# Check to see if we have a single coin match (BASE CASE)
if target in coins:
return 1
else:
# for every coin value that is <= than target
for i in [c for c in coins if c <= target]:
# Recursive Call (add a count coin and subtract from the target)
num_coins = 1 + rec_coin(target-i,coins)
# Reset Minimum if we have a new minimum
if num_coins < min_coins:
min_coins = num_coins
return min_coins
# rec_coin(63,[1,5,10,25])
# 6
这是我拆开后想出来的
1 + 63-1 coins + 62-1 + 61-1 and so on..
为什么要加1?展开递归的正确方法是什么
您提供的代码效率很低。为了找到数量为 63 的解决方案,假设它将首先以最小硬币(即 1)为步长递归到目标数量。然后在多次回溯和尝试其他硬币之后,它最终回溯到最外层并尝试价值 5 的硬币。现在递归再次开始,就像之前一样,添加价值 1 的硬币。但问题是,这中间值 (63-5) 之前已经被访问过(选择硬币 1 后深度为 5 层),并且需要大量函数调用才能获得该值 58 的结果。然而,该算法将忽略它并执行所有操作再次工作。
一个常见的解决方案是动态规划,即记忆早期找到的解决方案,以便无需额外工作即可重复使用。
我将在这里介绍一种自下而上的方法:它首先检查仅用一枚硬币可以达到的所有数量。这些金额被放入队列中。如果目标在其中,则答案为 1。如果不是,则通过将所有可能的硬币添加到每个硬币来处理队列中的所有金额。有时会发现一个值之前已经访问过,在这种情况下它不会被放入下一个队列,否则就是。如果现在目标值在该队列中,则您知道只需 2 个硬币即可达到目标值。
这个过程在循环中继续进行,这实际上只是在树中进行广度优先搜索,其中数量是节点,边表示通过向其中添加一个硬币可以从另一个数量达到一个数量。搜索从代表数量 0 的节点开始。
这是它的代码:
def rec_coin(target, coins):
visited = set() # Amounts that we have already achieved with a minimal number of coins
amounts = [0] # The latest series of amounts all using an equal number of coins
for min_coins in range(1, target+1):
next_amounts = []
for amount in amounts:
for coin in coins:
added = amount + coin
if added == target:
return min_coins
if not added in visited:
visited.add(added)
next_amounts.append(added)
amounts = next_amounts
print (rec_coin(63,[1,5,10,25]))
我正在尝试 unwind
此 algorithm
中的 recursive
函数。硬币找零问题:给定目标数量 n 和一个包含不同硬币价值的列表 array
,要达到找零数量所需的最少硬币是多少。
def rec_coin(target,coins):
# Default to target value
min_coins = target
# Check to see if we have a single coin match (BASE CASE)
if target in coins:
return 1
else:
# for every coin value that is <= than target
for i in [c for c in coins if c <= target]:
# Recursive Call (add a count coin and subtract from the target)
num_coins = 1 + rec_coin(target-i,coins)
# Reset Minimum if we have a new minimum
if num_coins < min_coins:
min_coins = num_coins
return min_coins
# rec_coin(63,[1,5,10,25])
# 6
这是我拆开后想出来的
1 + 63-1 coins + 62-1 + 61-1 and so on..
为什么要加1?展开递归的正确方法是什么
您提供的代码效率很低。为了找到数量为 63 的解决方案,假设它将首先以最小硬币(即 1)为步长递归到目标数量。然后在多次回溯和尝试其他硬币之后,它最终回溯到最外层并尝试价值 5 的硬币。现在递归再次开始,就像之前一样,添加价值 1 的硬币。但问题是,这中间值 (63-5) 之前已经被访问过(选择硬币 1 后深度为 5 层),并且需要大量函数调用才能获得该值 58 的结果。然而,该算法将忽略它并执行所有操作再次工作。
一个常见的解决方案是动态规划,即记忆早期找到的解决方案,以便无需额外工作即可重复使用。
我将在这里介绍一种自下而上的方法:它首先检查仅用一枚硬币可以达到的所有数量。这些金额被放入队列中。如果目标在其中,则答案为 1。如果不是,则通过将所有可能的硬币添加到每个硬币来处理队列中的所有金额。有时会发现一个值之前已经访问过,在这种情况下它不会被放入下一个队列,否则就是。如果现在目标值在该队列中,则您知道只需 2 个硬币即可达到目标值。
这个过程在循环中继续进行,这实际上只是在树中进行广度优先搜索,其中数量是节点,边表示通过向其中添加一个硬币可以从另一个数量达到一个数量。搜索从代表数量 0 的节点开始。
这是它的代码:
def rec_coin(target, coins):
visited = set() # Amounts that we have already achieved with a minimal number of coins
amounts = [0] # The latest series of amounts all using an equal number of coins
for min_coins in range(1, target+1):
next_amounts = []
for amount in amounts:
for coin in coins:
added = amount + coin
if added == target:
return min_coins
if not added in visited:
visited.add(added)
next_amounts.append(added)
amounts = next_amounts
print (rec_coin(63,[1,5,10,25]))