Coin Change Problem: DP and Recursion Approach
Outline of Article
- Naive approach - Brute Force Recursion
- Pro Approach - Dynamic Programming & Recursion [Optimal Time Complexity]
All codes are in C++, Java, and Python.
Introduction
Problem: Given a set of coins and a value 'V'. Find the number of ways
we can make a change of 'V'.
OR
You are given an array of coins of size n, each representing a coin of a distinct denomination. Target is another value that you are given. Discover the various combinations that make up the desired quantity. Consider that there are endless quantities of each type of coin.
Ex : Problem: S = {1,2,3} V = 3
Possible ways to make change are; {3}, {2,1}, {1,1,1}
Note: {1,2} are not counted as separate as it is the same as {2,1}
Naive Approach - Exponential Complexity
- We can use a brute force recursion to fix this issue crudely. We can try every conceivable combination of taking coins to equal the desired amount, adding them all up to determine how many ways there are to get the desired amount.
- The simplest scenario would be when we have no coins or when the goal is to reach zero.
- Time Complexity: O(targetn) // Exponential
- Space Complexity: O(targetn) // Exponential
int coinChange(vector<int> &coins, int n, int target) { |
Naive approach ends here. We will now learn the pro approach using DP and Recursion
Pro Approach - O(n) complexity
- Dynamic programming allows us to find a pseudo-polynomial-time solution to this issue.
- You'll see that the coin change() function performs a lot of recursive calls for the same parameter. So that the same function call is not made repeatedly, we memoize the function calls using a DP array.
- The number of ways we can reach the desired amount j using the first provided denominations is represented by DP[i][j] in our DP array in this case.
- Time Complexity: O(n * target)
- Space Complexity: O(n * target)
Dynamic Programming
vector<vector<int>> dp; |
ANOTHER C++ CODE
int numberOfCombinations(vector<int> coins, int target) { |
Python Code : Dynamic Programming
def numberOfCombinations(coins, target): |
This code is solving the coin change problem, by counting the number of ways of making change for a given amount using a given set of coin denominations. The function takes in two arguments: a list of coins and an target. It uses a 2D array dp and fills it using the bottom-up approach, also known as dynamic programming. The function returns the number of combinations of coins that can be used to make changes for the given target.
You would call the function like this:
numberOfCombinations([1, 2, 3], 4) |
Java Code: Dynamic Programming
public int numberOfCombinations(int[] coins, int target) { |
Call function like this:
int result = numberOfCombinations(new int[]{1, 2, 3}, 4); |
Consider the problem of making change for a smaller amount and add a coin of the largest denomination that is less than or equal to the remaining amount. Here is an example of a Python function that solves the coin exchange problem.
Recursion
def make_change(amount, denominations): |
Explanation for the code:
This function takes in two arguments: an amount to make change for and a list of denominations of coins. It uses recursion to consider two possibilities: using the largest coin denomination or not using it, and returns the solution with the fewest number of coins.
You would call the function like this:
make_change(100, [1, 5, 10, 25]) |
Here the dynamic programming code ends. now we will learn the coin exchange problem using recursion with optimal time complexity.
C++ Code: Recursion
#include <vector> |
Call the Function like this:
std::vector<int> result = make_change(100, {1, 5, 10, 25}); |
It will return the vector of coin denomination which makes change for 100.
Note that in C++, you will have to include <vector> and <algorithm> to use vector and min functions respectively.
Here is an example of a Java function that solves the coin exchange problem using recursion:
import java.util.ArrayList; |
You call the function like this :
List<Integer> result = CoinExchange.makeChange(100, new int[]{1, 5, 10, 25}); |
It will return the list of coin denomination which makes change for 100.
Note that in this code, I have used ArrayList and Integer.