Yilmaz
Yilmaz

Reputation: 49661

Coin change leetcode in python

I tried to solve on my own the LeetCode problem 322. Coin Change:

You are given an integer array coins representing coins of different denominations and an integer amount representing a total amount of money.

Return the fewest number of coins that you need to make up that amount. If that amount of money cannot be made up by any combination of the coins, return -1.

You may assume that you have an infinite number of each kind of coin.

I seem to have a bug and cannot figure it out.

I am solving with DFS, basically saying when the target hits 0, just gather all the nums in an array and dynamically keep the shortest possible result. This is the decision tree for the problem:

enter image description here

This is my solution:

from typing import List
class Solution:
    def coinChange(self, nums: List[int], target: int) -> int:      
        def dfs(remainder):
            if remainder<0:
                return None
            if remainder==0:
                return []         
            shortest_combination=None
            for num in nums:
                print("target",remainder)
                print("num",num)             
                result=dfs(remainder-num)
                if result!=None:                    
                    combination=[*result,num]                    
                    if shortest_combination==None or len(combination)<len(shortest_combination):                        
                        shortest_combination=combination                    
            return shortest_combination       
        return -1 if dfs(target)==None else len(dfs(target))
    
        
    
s=Solution()
s.coinChange([1,2,5],100)

I print num and remainder, and I see that for some reason remainder never hits 0. Based on DFS, if I keep subtracting 1 from 100 I should be reaching 0, but somehow it does not reach it with any num.

Upvotes: 1

Views: 1861

Answers (2)

trincot
trincot

Reputation: 351029

Your algorithm is correct, it really does hit 0, but in that case you don't print it (function exits before printing). Adding more debugging you'll see it does reach that base case and backtracks and correctly identifies the sub-solutions.

The problem really is that the tree you are visiting with DFS is exponentially large, whereby you solve the same problem a multitude of times. If you add a few lines of code to implement memoization, you'll see it does the job:

from typing import List

class Solution:
    def coinChange(self, nums: List[int], target: int) -> int:
        memo = {}  # used for memoization
        def dfs(remainder):
            if remainder in memo:  # already solved this problem?
                return memo[remainder]  # then return what we got last time
            if remainder<0:
                return None
            if remainder==0:
                return []         
            shortest_combination=None
            for num in nums:
                result = dfs(remainder-num)
                if result!=None:
                    combination=[*result,num]
                    if shortest_combination==None or len(combination)<len(shortest_combination):
                        shortest_combination=combination                    
            memo[remainder] = shortest_combination  # memoize this solution
            return shortest_combination

        return -1 if dfs(target)==None else len(dfs(target))


s=Solution()
print(s.coinChange([1,2,5],100))  # 20

Upvotes: 0

Frank Yellin
Frank Yellin

Reputation: 11297

This problem needs to be solved using dynamic programming. Given any value, assume you've already calculated the smallest number of coins to generate 0, ... value - 1, To calculate the smallest number of coins for value, look at the number of coins needed for value - coin1, value - coin2, value - coin3, ..., pick the smallest, and add one.

Actually coding this is something you should do on your own.

Upvotes: 0

Related Questions