I'm working on LeetCode 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.
Example:
Input: coins = [1,2,5], amount = 11
Output: 3
Explanation: 11 = 5 + 5 + 1
I choose a top-down approach where at each iteration I choose a coin whose denomination is not greater than the remaining amount. Sounds easy, right?
The following code passes all test cases.
import sys
import functools
class Solution:
def coinChange(self, coins: List[int], amount: int) -> int:
@functools.cache
def _loop(remaining: int) -> int:
if remaining == 0:
return 0
y = sys.maxsize
for coin in filter(lambda x: x <= remaining, coins):
y = min(y, _loop(remaining - coin))
return (y + 1) if y < sys.maxsize else y
num_coins = _loop(amount)
return num_coins if num_coins < sys.maxsize else -1
But this one doesn't.
import sys
class Solution:
def coinChange(self, coins: List[int], amount: int) -> int:
num_coins = self._loop(coins, amount, 0, {})
return num_coins if num_coins < sys.maxsize else -1
def _loop(self, coins: Sequence[int], remaining: int, count: int, memo: MutableMapping[int, int]) -> int:
if remaining == 0:
return count
if remaining not in memo:
y = sys.maxsize
for coin in filter(lambda x: x <= remaining, coins):
y = min(y, self._loop(coins, remaining - coin, count + 1, memo))
memo[remaining] = y
return memo[remaining]
The only difference between the two solutions is that in the former, 1
is added to the result after the for
loop (because one coin has been used), and in the latter, 1
is added to the parameter to the recursive call.
What is the bug in the second solution that I'm not seeing?