Coin Change 2
LeetCode Problem #518 (Medium)
Problem Statement
You are given coins of different denominations and a total amount of money. Write a function to compute the number of combinations that make up that amount. You may assume that you have an infinite number of each kind of coin.
Testcases
Problem Explanation
We are given a set of coins, each of different denominations. In this problem, we must find out the total number of unique ways to generate a particular amount of money, only using the given coins.
Prerequisite Knowledge
Dynamic Programming
Dynamic Programming is a programming paradigm in which a large problem can be simplified by breaking it down into smaller sub-problems which yield solutions which could be used to find the final solution.
Typically, a problem can be solved using dynamic programming if it follows two prerequisite conditions:
Optimal Substructure—An optimal solution can be generated from the optimal solutions of its sub-problems.
Overlapping Subproblems—The problem can be broken down into sub-problems which can be reused multiple times.
Intuitively, we would begin to solve a dynamic programming problem by first finding its recursive solution. However, using recursion would yield an exponential time complexity which is sub-optimal for large problems.
Generally, dynamic programming follows a bottom-up approach wherein, each sub-problem must be solved at least once. For this purpose, an n-dimensional table is usually filled by solving all related sub-problems.
Memoization
This is an optimization technique that is often used in conjunction with dynamic programming wherein, a map of already computed sub-problems is maintained and the result of this problem may be utilized at further stages of the solution.
This technique uses a top-down approach since you essentially solve the "top problem" before recursively solving the sub-problems below it.
Memoization could be described as recursive dynamic programming since it is often used to implement dynamic programming.
Approach
General Approach
Consider the following example:
In order to compute the total number of distinct ways that we can generate that amount of change from the given denominations, we must perform two actions repeatedly:
Calculate the number of solutions when the largest coin value is considered to be a part of the list of denominations.
Calculate the number of solutions when the largest coin value is removed from the list of denominations.
A solution is only considered if exact change can be produced. In this case, this means that the amount of change left at the end of the processing is 0.
If a negative value of change is obtained or there are no more coins left to process, then the solution is not considered.
At each stage of the solution, we consider a certain coin and see how it affects the total number of ways to generate the given amount.
In the tree representation, the main problem is divided into two parts to represent the actions that need to be performed as described above:
Left Branch: Considering the largest coin value by subtracting it from the total amount.
Right Branch: Not considering the largest coin value by removing it from the list of coins.
Recursive Solution
In the recursive solution, we solve for every sub-problem irrespective of whether we have seen and solved that problem before. The tree quickly becomes very large in order to accommodate the solution for every sub-problem. The solutions highlighted in green represent solutions that can be counted as a part of the final answer.
Memoization Solution
In the memoization solution, we initally begin with the same approach by dividing the main problem into two-sub problems. However, when we encounter a sub-problem that we have already solved, we simply retrieve the solution from that problem and use it in order to avoid re-computation of known sub-problems. The tree is significantly smaller in this case when compared to the recursive approach.
Source of Images:
Algorithm
Top-Down DP Approach
In this approach, we use a top-down approach to break down the large problem into simpler sub-problems.
Initialize a one-dimensional vector to build the dynamic programming table.
Iterate through every coin value.
Build the table by adding the current value with the value at position (i - coin).
Return the value at the end of the array.
Code
Last updated
Was this helpful?