![]() |
VOOZH | about |
Given an integer array coins[ ] representing different denominations of currency and an integer sum. We need to find the number of ways we can make sum by using different combinations from coins[ ].
Note: Assume that we have an infinite supply of each type of coin. Therefore, we can use any coin as many times as we want.
Examples:
Input: sum = 4, coins[] = [1, 2, 3]
Output: 4
Explanation: There are four solutions: [1, 1, 1, 1], [1, 1, 2], [2, 2] and [1, 3]Input: sum = 10, coins[] = [2, 5, 3, 6]
Output: 5
Explanation: There are five solutions:
[2, 2, 2, 2, 2], [2, 2, 3, 3], [2, 2, 6], [2, 3, 5] and [5, 5]
Table of Content
To solve this problem initially, we use recursion because at every step we have a choice: either we include the current coin or we do not include it.
For each coin, there are two possibilities:
- Include the current coin
If we pick the current coin, then its value reduces the remaining target sum. Because coins are available in infinite supply, we can include the same coin again.
So the recursive call becomes: count(coins, n, sum - coins[n-1])- Exclude the current coin
If we decide not to pick the current coin, then we move to the previous coin while keeping the target sum unchanged.
So the recursive call becomes: count(coins, n-1, sum)Since we are looking for all different combinations that form the given sum, the final answer will be the sum of both possibilities (include + exclude).
5
In the previous recursive approach, we observed that many subproblems are solved repeatedly. This repetition increases time complexity. To handle this, we use Memoization.
We create a DP table of size n × (sum + 1), because the result of the recursion depends on two changing parameters: the number of coins considered and the remaining target sum So whenever we compute a subproblem count(i, sum), we store the result in the DP table. Next time when the same subproblem appears, instead of computing it again, we directly fetch it from the DP table, which saves a lot of time.
5
In the memoization approach we solved each subproblem top-down using recursion, but in the tabulation approach we build the solution in a bottom-up manner by filling a DP table iteratively.
We first define the base cases for the DP table.
- dp[0][0] = 1, meaning if we have 0 coins and target sum is 0, there is exactly one way — choose nothing.
- For dp[0][j] where j > 0, the value is 0 because with zero coins we cannot make a positive sum.
- For dp[i][0], the value is 1 for all i because there is only one way to make sum 0 — by not selecting any coin.
After the base initialization, we fill the table iteratively using the same idea.
5
In previous approach of dynamic programming we have derive the relation between states as given below:
- if (sum-coins[i]) is greater than 0, then dp[i][sum] = dp[i][sum-coins[i]] + dp[i+1][sum].
- else dp[i][sum] = dp[i+1][sum].
If we observe that for calculating current dp[i][sum] state we only need previous row dp[i-1][sum] or current row dp[i][sum-coins[i]]. There is no need to store all the previous states just one previous state is used to compute result.
5
Related articles: