You are given an integer array coins representing coins of different denominations (e.g. 1 dollar, 5 dollars, etc) and an integer amount representing a target amount of money.
Return the number of distinct combinations that total up to amount. If it's impossible to make up the amount, return 0.
You may assume that you have an unlimited number of each coin and that each value in coins is unique.
Example 1:
Input: amount = 4, coins = [1,2,3]
Output: 4Explanation:
Example 2:
Input: amount = 7, coins = [2,4]
Output: 0Constraints:
1 <= coins.length <= 1001 <= coins[i] <= 50000 <= amount <= 5000
You should aim for a solution as good or better than O(n * a) time and O(n * a) space, where n is the number of coins and a is the given amount.
As we need to find the total number of combinations, think in terms of recursion and visualize it as a decision tree where multiple coin choices are available at each recursion step. Can you determine a way to allow picking the same coin multiple times? Maybe you should consider the decisions made at each recursion step.
The given coins are unique. We recursively iterate through the coins array using index i, tracking the collected amount along the current path. At each step, we can either skip the current coin or pick it, ensuring the total does not exceed the target. To allow picking the same coin multiple times, we recurse with the same index but an updated amount, generating different combinations.
If we reach the target amount, we return 1. The recursion stops if the index goes out of bounds. We count all possible ways and return the total. This approach is exponential. Can you think of a way to optimize it? Maybe you should consider an approach to avoid redundant computations.
We can use memoization to cache the results of recursive calls and avoid redundant computations. A hash map or a 2D array can be used to store these results.
class Solution:
def change(self, amount: int, coins: List[int]) -> int:
coins.sort()
def dfs(i, a):
if a == 0:
return 1
if i >= len(coins):
return 0
res = 0
if a >= coins[i]:
res = dfs(i + 1, a)
res += dfs(i, a - coins[i])
return res
return dfs(0, amount)Where is the number of coins, is the given amount and is the minimum value among all the coins.
class Solution:
def change(self, amount: int, coins: List[int]) -> int:
coins.sort()
memo = [[-1] * (amount + 1) for _ in range(len(coins) + 1)]
def dfs(i, a):
if a == 0:
return 1
if i >= len(coins):
return 0
if memo[i][a] != -1:
return memo[i][a]
res = 0
if a >= coins[i]:
res = dfs(i + 1, a)
res += dfs(i, a - coins[i])
memo[i][a] = res
return res
return dfs(0, amount)Where is the number of coins and is the given amount.
class Solution:
def change(self, amount: int, coins: List[int]) -> int:
n = len(coins)
coins.sort()
dp = [[0] * (amount + 1) for _ in range(n + 1)]
for i in range(n + 1):
dp[i][0] = 1
for i in range(n - 1, -1, -1):
for a in range(amount + 1):
if a >= coins[i]:
dp[i][a] = dp[i + 1][a]
dp[i][a] += dp[i][a - coins[i]]
return dp[0][amount]Where is the number of coins and is the given amount.
class Solution:
def change(self, amount: int, coins: List[int]) -> int:
dp = [0] * (amount + 1)
dp[0] = 1
for i in range(len(coins) - 1, -1, -1):
nextDP = [0] * (amount + 1)
nextDP[0] = 1
for a in range(1, amount + 1):
nextDP[a] = dp[a]
if a - coins[i] >= 0:
nextDP[a] += nextDP[a - coins[i]]
dp = nextDP
return dp[amount]Where is the number of coins and is the given amount.
class Solution:
def change(self, amount: int, coins: List[int]) -> int:
dp = [0] * (amount + 1)
dp[0] = 1
for i in range(len(coins) - 1, -1, -1):
for a in range(1, amount + 1):
dp[a] += dp[a - coins[i]] if coins[i] <= a else 0
return dp[amount]Where is the number of coins and is the given amount.