Problem
You are given:
- coins: An integer array representing coins of different denominations.
- counts: An integer array where
counts[i]
represents the maximum number of coins available for the denominationcoins[i]
. - amount: An integer representing the total amount of money to form.
You need to compute the number of distinct ways to form amount
using the given denominations under the constraints that each denomination has a limited count.
Examples
Example 1
|
|
Example 2
|
|
Solution
Method 1 - Using Recursion
The naive recursive approach involves trying all possible combinations of coins for each denomination while respecting their availability constraints (limited counts). It explores every possible way to form the amount
using the given denominations and their respective counts.
Approach
- Base Case:
- If
amount == 0
, return 1 (a valid way is found). - If
amount < 0
or there are no denominations left, return 0 (not a valid way).
- If
- Recursive Step:
- For each denomination, try using it from
0
tocounts[i]
times and recursively solve the subproblem for the reducedamount
and updatedcounts
.
- For each denomination, try using it from
The naive recursive approach is inefficient due to overlapping subproblems, but it is useful for understanding the problem.
Code
|
|
|
|
|
|
Complexity
- ⏰ Time complexity:
O(counts[0] * counts[1] * ... * counts[n])
, wheren
is the number of denominations. This is because we try every possible combination of coins. - 🧺 Space complexity:
O(amount)
, due to the recursion stack.
Method 2 - Using Top-down approach
The naive recursive approach can be optimised using memoization, which avoids recomputing overlapping subproblems. In this approach:
- Use a
memo
dictionary (or array) to store previously computed results for specificindex
andremaining
values. - This ensures that the function does not recompute the number of ways for the same state multiple times.
Algorithm
- Define a recursive function
helper(index, remaining)
that calculates the number of ways to form theremaining
amount using coins starting from the givenindex
. - Use a dictionary or array
memo
to store computed results for(index, remaining)
to avoid recomputation. - Modify the recursive approach:
- Before computing the result for the current state
(index, remaining)
, check whether it already exists inmemo
. - If it exists, return the stored result.
- Otherwise, compute the result recursively, store it in
memo
, and return it.
- Before computing the result for the current state
Code
|
|
|
|
|
|
Complexity
- ⏰ Time complexity:
O(amount * len(coins) * max(counts))
len(coins)
is the number of denominations.max(counts)
is the maximum number of repetitions we can try for each coin.amount
is the dimension of the memoisation table.
- 🧺 Space complexity:
O(amount * len(coins))
- Space is used for the memoisation table.
- Maximum depth of recursion stack is
O(len(coins)
.
Method 3 - Using bottom-up DP (1D array)
Reasoning or Intuition
- This is a variation of the coin change problem with the additional constraint of limited counts for each denomination.
- To solve it, we need to track both the amount we aim to form (
amount
) and the number of coins available for each denomination (counts
). - A dynamic programming approach can be used:
- Define a DP table
dp[amount+1]
wheredp[i]
represents the number of ways to form the amounti
. - For each coin and its count, update the DP table by considering each valid usage of the coin (from
0
tocounts[i]
).
- Define a DP table
Approach
- Construct an array
dp
wheredp[i]
denotes the number of distinct ways to formi
. - Initialize
dp[0] = 1
since there is one way to form amount0
(by using no coins). - For every coin, iterate through the array
dp
in the reverse direction (to handle limited counts for each denomination). - For each amount
j
, iterate from1
tocounts[i]
(representing the number of times we use the current coin) to calculate contributions. - Return
dp[amount]
as the final answer.
Code
|
|
|
|
|
|
Complexity
- ⏰ Time complexity: -
O(amount * sum(counts))
, wheresum(counts)
is the sum of maximum usages for all denominations. - 🧺 Space complexity: -
O(amount)
, because thedp
array requires space proportional to theamount
.