0

this my code. The task of changing coins. I need to get a list of lists, with exchange options.

a = []
def coinChange(coins, amount, result=None):
    if result is None: 
        result = []
    
    if amount < 1 and sum(result) == 3:
        return a.append(result)

    else:
        for i in coins:
            if amount - i >= 0:
                result.append(i)
                coinChange(coins, amount - i, result)            
    return 

coinChange([1,2,3], 3)
print(a)

They return

[1,1,1,2,2,1,3]

But I need to get a list of lists. Each sublist should contain only those numbers that add up to 3.

For Example:

[[1,1,1], [2,1], [3]]

How do i get such a list? thank

Will Ness
  • 70,110
  • 9
  • 98
  • 181
Harry
  • 39
  • 6
  • `return a.append(result)` will always return None [see](https://stackoverflow.com/questions/16641119/why-does-append-always-return-none-in-python#:~:text=It%20is%20a%20convention%20in,that%20mutate%20sequences%20return%20None%20.&text=The%20methods%20that%20add%2C%20subtract,collection%20instance%20itself%20but%20None%20.) – DarrylG Sep 13 '20 at 14:29
  • To see what might be happening: Did you step through the execution with your IDE's debugging features? Or by hand with pencil and paper? Or with the Python debugger [pdb] module? Or by printing stuff at different points in the code? – wwii Sep 13 '20 at 14:39
  • I have been solving this problem for more than 15 hours, I have tried both paper and pencil and everything I can. Code problem. – Harry Sep 13 '20 at 14:41
  • I just don't know how to make sublists with a sum of 3. – Harry Sep 13 '20 at 14:42

2 Answers2

3

I would even take DarrylG's answer further and advise against passing results through the recursion stack, as it complicates the whole idea of recursions.

Simply put, you should usually:

  1. Assume you can solve a smaller version of your problem (which is the exact function you are implementing)
  2. Solve the original problem using the solutions of the smaller problems (the recursive step, here you call the function)
  3. Define an explicit solution for the simplest case you have for your problem, which is essentially the recursion's stopping condition.

Here is an example code for solving the problem with these tips:

def coinChange(coins, sum):
    # Stop condition.
    if sum == 0:
        return [[]]

    # Recursive step
    solutions = []
    for i, coin in enumerate(coins):
        if coin <= sum:
            lst = coinChange(coins[i:], sum - coin)
            solutions.extend([[coin] + l for l in lst])

    return solutions


print(coinChange([1, 2, 3], 3))

result of running:

[[1, 1, 1], [1, 2], [3]]

nice test for checking if you did these steps without dependency is trying to one-line your code:

def coinChange(coins, sum):
    return [[c] + l for i, c in enumerate(coins) if c <= sum for l in coinChange(coins[i:], sum - c)] if sum > 0 else [[]]

note that sometimes it might be unreadable, so it's your decision weather to keep it in one-line form.

GalSuchetzky
  • 785
  • 5
  • 21
1

Simple solution

Code

def coinChange(coins, amount, result=None, solutions = None):
    '''
        result - stores current set of coins being tries
        soltions - solutions found so far
    '''
    if result is None: 
        result = []
        
    if solutions is None:
        solutions = []

    if amount == 0:
        # Add solution
        solutions.append(result[:])  # append a copy since result will change
    elif amount > 0:
        for i in coins:
            if amount - i >= 0:
                # Adding i to list of coins to try
                coinChange(coins, amount - i, result + [i,], solutions)
                
    return solutions
            

Test

a = coinChange([1,2,3], 3)
print(a)
            
# Capture the solution in a (i.e. don't make it global--generally bad practice)         
a = coinChange([1,2,3], 3)
print(a)

Output

[[1, 1, 1], [1, 2], [2, 1], [3]]

Even Simpler Using Generators

def coinChange(coins, amount, result=None):
    '''
        result - stores current set of coins being tries
        soltions - solutions found so far
    '''
    if result is None: 
        result = []
        
    if amount == 0:
        # report solution
        yield result
        
    if amount > 0:
        for i in coins:
            yield from coinChange(coins, amount - i, result + [i,])    
            
a = list(coinChange([1,2,3], 3))
print(a)

Using Cache

Easiest to illustrate use of cache by modifying GalSuchetzky answer.

Issue

  • Can't directly use cache on coinChange function since arguments are not hashable (e.g. coins is a list, so not hashable)
  • We get back this by using a nested function (helper) whose arguments are hashable that indexes into coins as necessary

Code

def coinChange(coins, sum_):
    '''
        Inputs:
            coins - list of coins
            sum_  - value coin should sum to (use sum_ since sum is a builtin function)
    '''
    
    def coinChangeHelper(j, total):
        '''
            Uses cache to compute solutions
            
            Need helper function since coins is a list so can't be hashed to placed in cache
            
            Inputs:
                j     - current index into coins
                total - current sum
        '''
        if (j, total) in mem_cache:
            # Use cache value
            return mem_cache[(j, total)]
        
        # Stop condition.
        if total == 0:
            mem_cache[(j, total)] = [[]]
        else:
            # Recursive step
            solutions = []

            for i in range(j, len(coins)):
                if coins[i] <= total:
                    lst = coinChangeHelper(i, total - coins[i])
                    solutions.extend([[coins[i]] + l for l in lst])

            mem_cache[(j, total)] = solutions
        
        return mem_cache[(j, total)]

    # Init cache
    mem_cache = {}
    
    return coinChangeHelper(0, sum_)

print(coinChange([1, 2, 3], 3))
DarrylG
  • 16,732
  • 2
  • 17
  • 23
  • @Igor--updated to show how a cache could be used (using GalSuchetzky answer since its simpler to cache). Wasn't sure if you're familiar with decorators so did the cache as shown. If you are let me know, then I could show you a shorter version. – DarrylG Sep 13 '20 at 20:50
  • Thanks for you code! your code is cool, but A good solution would be to take the first code. And insert the cache into it. yes, you can use a decorator if it is part of the standard Python suite. – Harry Sep 23 '20 at 22:42
  • @Igor--issue is the first solution is hard to cache since it's arguments includes lists i.e. coinChange(coins, amount, result=None, solutions = None), we have coins, results and solutions as lists which are not hashable. In the version with the recursive inner function i.e. coinChangeHelper(j, total), it's arguments are two integers which are hashable. – DarrylG Sep 23 '20 at 23:02
  • @ DarrylG Thank you, yes, I got it and figured it out! Solution works fine – Harry Sep 24 '20 at 00:00