-2

I am trying to unwind the recursive function in this algorithm. Coin change problem: Given a target amount n and a list array of distinct coin values, what's the fewest coins needed to make the change amount.

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

This is what I come up with after breaking it apart

1 + 63-1 coins + 62-1 + 61-1 and so on..

why do we need to add 1? What would be the correct way of unwiding the recursion

Jogendar Choudhary
  • 3,241
  • 1
  • 9
  • 23
edmamerto
  • 4,841
  • 6
  • 30
  • 46

1 Answers1

1

The code you present is very inefficient. For finding the solution for an amount of 63, imagine that it will first recurse to the target amount with steps of the smallest coin (i.e. 1). Then after a lot of backtracking and attempts with other coins, it finally backtracks to the outermost level and tries a coin with value 5. Now the recursion kicks in again, just like before, adding coins of value 1. But the problem is that this intermediate value (63-5) was already visited before (5 levels deep after picking coin 1), and it took a lot of function calls to get results for that value 58. And yet, the algorithm will just ignore that and do all of that work again.

A common solution to this is dynamic programming, i.e. memoizing earlier found solutions so they can be reused without extra work.

I will present here a bottom-up method: it first checks all amounts that can be achieved with just one coin. These amounts are put in a queue. If the target is among them then the answer is 1. If not, all amounts in the queue are processed by adding all possible coins to each of them. Sometimes a value will be found that was already visited before, and in that case it is not put in the next queue, but otherwise it is. If now the target value is in that queue, you know that target can be reached with just 2 coins.

This process continues in a loop, which is in fact just a Breadth-first-search in a tree where amounts are nodes, and edges represent that one amount can be reached from another by adding one coin to it. The search starts in the node that represents an amount of 0.

Here is the code for it:

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]))
trincot
  • 211,288
  • 25
  • 175
  • 211