Date and Time: Aug 25, 2024, 23:26 (EST)
Link: https://leetcode.com/problems/coin-change-ii/
You are given an integer array coins
representing coins of different denominations and an integer amount
representing a total amount of money.
Return the number of combinations that make up that amount. If that amount of money cannot be made up by any combination of the coins, return 0
.
You may assume that you have an infinite number of each kind of coin.
The answer is guaranteed to fit into a signed 32-bit integer.
Example 1:
Input: amount = 5, coins = [1,2,5]
Output: 4
Explanation: there are four ways to make up the amount:
5=5
5=2+2+1
5=2+1+1+1
5=1+1+1+1+1
Example 2:
Input: amount = 3, coins = [2]
Output: 0
Explanation: the amount of 3 cannot be made up just with coins of 2.
Example 3:
Input: amount = 10, coins = [10]
Output: 1
-
1 <= coins.length <= 300
-
1 <= coins[i] <= 5000
-
All the values of
coins
are unique. -
0 <= amount <= 5000
2D DP:
-
We can build a
(amount + 1) * (coins + 1)
dp table, which eachdp[a][c]
indicates the number of ways we can usec
in coins to achievea
in amount. We first initializedp[0]
to be all1
, because the only way for all coins to achieve0
is not using coins. -
We then loop over
(1, amount + 1)
, and visiting the coins backward to fill out the dp table from top to bottom, right to left. -
Because the last column is the base case, so each time we intialize an entry in dp, we do
dp[a][c] = dp[a][c-1]
to first assign the new entry to be the value of its previous coin, because this new coin should have at least the number of ways of the previous coin to achievea
, then we check ifa - coins[c] >= 0
, so we know this new coinc
can help to achievea
, then we add the rowdp[a - coins[c]]
's number of ways todp[a][c]
. -
The final value is the last row, first element of the dp table.
1 2 5
0 [[1, 1, 1, 1],
1 [1, 0, 0, 0],
2 [2, 1, 0, 0],
3 [2, 0, 0, 0],
4 [3, 1, 0, 0],
5 [4, 1, 1, 0]]
dp[a][i] = dp[a][i-1] + dp[a-1][i]
5 4 3 2 1 0
1 4 3 2 2 1 1
2 1 1 0 1 0 1
5 1 0 0 0 0 1
Optimized 1d DP:
-
The optimized version we only store the previous column as
prev
, which is initialized to be all0
and the first row will be1
fora = 0
. In the for loop we initialize a new columndp
to store this column for current coinc
for each amounta
. -
We repeatedly update
prev = dp
from right to left. And return the last element ofdp
as the final result.
class Solution:
def change(self, amount: int, coins: List[int]) -> int:
dp = [[0] * (len(coins)+1) for _ in range(amount + 1)]
dp[0] = [1] * (len(coins)+1)
for a in range(1, amount+1):
for c in range(len(coins)-1, -1, -1):
dp[a][c] = dp[a][c+1]
if a - coins[c] >= 0:
dp[a][c] += dp[a-coins[c]][c]
return dp[-1][0]
Time Complexity: m
is amount, n
is length of coins
.
Space Complexity:
class Solution:
def change(self, amount: int, coins: List[int]) -> int:
prev = [0] * (amount+1)
prev[0] = 1
for c in range(len(coins)-1, -1, -1):
dp = [0] * (amount+1)
dp[0] = 1 # a = 0 is always 1
for a in range(1, amount+1):
dp[a] = prev[a] # Store previous col
if a - coins[c] >= 0:
dp[a] += dp[a-coins[c]]
prev = dp
return dp[amount]
Time Complexity: m
is amount, n
is length of coins
.
Space Complexity: