Coin Change Problem in C++
Last Updated :
07 Aug, 2024
In this article, we will learn how to count all combinations of coins to make a given value sum using the C++ programming language. The Coin Change Problem involves finding the number of ways to make change for a given amount using a set of coin denominations.
Example:
Consider an integer array coins[] representing different coin denominations and an integer amount, determine the number of combinations of coins that sum up to the given amount.
Input:
coins = [1, 2, 5]
amount = 5
Output:
4
Explanation:
The different combinations are:
1) 1 + 1 + 1 + 1 + 1
2) 1 + 1 + 1 + 2
3) 1 + 2 + 2
4) 5
How to Solve Coin Change Problem in C++?
1. Count All Combinations Using Recursion
In the recursive approach, we will generate all possible combinations and count those that sum to the given amount using recursion.
Recurrence Relation:
count(coins,n,sum) = count(coins,n,sum-count[n-1]) + count(coins,n-1,sum)
Coin Change Using RecursionApproach:
- Base Condition:
- If the amount is 0, there is one way to make change (using no coins), so return 1.
- If the amount is negative or there are no coins left, return 0 as no valid combination can be formed.
- For each coin, recursively count the combinations by
- including the coin (reduce the amount by the coin's value) and
- excluding the coin (move to the next coin).
Below is the implementation of the above approach:
C++
// C++ program to solve coin change problem using recursion
#include <iostream>
#include <vector>
using namespace std;
// Returns the count of ways we can
// sum coins[0...n-1] coins to get sum "sum"
int count(int coins[], int n, int sum)
{
// If sum is 0 then there is 1 solution
// (do not include any coin)
if (sum == 0)
return 1;
// If sum is less than 0 then no
// solution exists
if (sum < 0)
return 0;
// If there are no coins and sum
// is greater than 0, then no
// solution exist
if (n <= 0)
return 0;
// count is sum of solutions (i)
// including coins[n-1] (ii) excluding coins[n-1]
return count(coins, n, sum - coins[n - 1]) + count(coins, n - 1, sum);
}
int main()
{
int i, j;
int coins[] = {1, 2, 3};
int n = sizeof(coins) / sizeof(coins[0]);
int sum = 5;
cout << " " << count(coins, n, sum);
return 0;
}
Time Complexity: O(2sum)
Auxiliary Space: O(sum)
2. Count All Combinations Using Dynamic Programming (Memoization)
We can further optimize the recursive solution by storing the results of previously solved subproblems in a 2D array to avoid redundant calculations.
Approach:
- Initialize Memoization Table by creating a 2D array dp of size (n+1) x (amount+1) and initialize all values to -1.
- For each subproblem:
- if the result is already computed, return it from the table.
- Otherwise, compute the result recursively, store it in the memoization table, and return the stored value.
Below is the implementation of the above approach:
C++
// C++ program to solve coin change problem using Dynamic Programming (Memoization
#include <iostream>
#include <vector>
using namespace std;
// Recursive function to count the numeber of distinct ways
// to make the sum by using n coins
int count(vector<int> &coins, int n, int sum, vector<vector<int>> &dp)
{
// Base Case
if (sum == 0)
return dp[n][sum] = 1;
// If number of coins is 0 or sum is less than 0 then
// there is no way to make the sum.
if (n == 0 || sum < 0)
return 0;
// If the subproblem is previously calculated then
// simply return the result
if (dp[n][sum] != -1)
return dp[n][sum];
// Two options for the current coin
return dp[n][sum] = count(coins, n, sum - coins[n - 1], dp) + count(coins, n - 1, sum, dp);
}
int32_t main()
{
int tc = 1;
// cin >> tc;
while (tc--)
{
int n, sum;
n = 3, sum = 5;
vector<int> coins = {1, 2, 3};
// 2d dp array to store previously calculated
// results
vector<vector<int>> dp(n + 1, vector<int>(sum + 1, -1));
int res = count(coins, n, sum, dp);
cout << res << endl;
}
}
Time Complexity: O(N*sum), where N is the number of coins and sum is the target sum.
Auxiliary Space: O(N*sum)
3. Count All Combinations Using Dynamic Programming (Tabulation)
We can use the bottom-up approach by building the solution iteratively using a table to store intermediate results.
Approach:
- Create a 2D dp array with rows and columns equal to the number of coin denominations and target sum.
- dp[0][0] will be set to 1 which represents the base case where the target sum is 0, and there is only one way to make the change by not selecting any coin.
- Iterate through the rows of the dp array (i from 1 to n), representing the current coin being considered.
- The inner loop iterates over the target sums (j from 0 to sum).
- Add the number of ways to make change without using the current coin, i.e., dp[i][j] += dp[i-1][j].
- Add the number of ways to make change using the current coin, i.e., dp[i][j] += dp[i][j-coins[i-1]].
- dp[n][sum] will contain the total number of ways to make change for the given target sum using the available coin denominations.
Below is the implementation of above approach:
C++
// C++ program to solve coin change problem using Dynamic Programming (Tabulation)
#include <iostream>
#include <vector>
using namespace std;
// Returns total distinct ways to make sum using n coins of
// different denominations
int count(vector<int> &coins, int n, int sum)
{
// 2d dp array where n is the number of coin
// denominations and sum is the target sum
vector<vector<int>> dp(n + 1, vector<int>(sum + 1, 0));
// Represents the base case where the target sum is 0,
// and there is only one way to make change: by not
// selecting any coin
dp[0][0] = 1;
for (int i = 1; i <= n; i++)
{
for (int j = 0; j <= sum; j++)
{
// Add the number of ways to make change without
// using the current coin,
dp[i][j] += dp[i - 1][j];
if ((j - coins[i - 1]) >= 0)
{
// Add the number of ways to make change
// using the current coin
dp[i][j] += dp[i][j - coins[i - 1]];
}
}
}
return dp[n][sum];
}
// Driver Code
int main()
{
vector<int> coins{1, 2, 3};
int n = 3;
int sum = 5;
cout << count(coins, n, sum);
return 0;
}
Time complexity : O(N*sum)
Auxiliary Space : O(N*sum)
4. Count All Combinations Using Dynamic Programming (Space Optimized)
In the above tabulation approach we are only using dp[i-1][j] and dp[i][j] , so we can further optimize the space complexity of the tabulation method by using only a 1D array.
Approach:
- Create a 1D dp array, dp[i] represents the number of ways to make the sum i using the given coin denominations.
- The outer loop iterates over the coins, and the inner loop iterates over the target sums. For each dp[j], it calculates the number of ways to make change using the current coin denomination and the previous results stored in dp.
- dp[sum] contains the total number of ways to make change for the given target sum using the available coin denominations. This approach optimizes space by using a 1D array instead of a 2D DP table.
Below is the implementation of the above approach:
C++
// C++ program to solve coin change problem using Dynamic Programming (Space Optimized)
#include <cstring> // Include the cstring header for memset
#include <iostream>
#include <vector>
using namespace std;
int count(const vector<int> &coins, int n, int sum)
{
// dp[i] will be storing the number of solutions for value i.
// We need sum+1 rows as the dp is constructed in bottom up manner using the base case (sum = 0)
vector<int> dp(sum + 1, 0);
// Base case (If given value is 0)
dp[0] = 1;
// Pick all coins one by one and update the table values after
// the index greater than or equal to the value of the picked coin
for (int i = 0; i < n; i++)
{
for (int j = coins[i]; j <= sum; j++)
{
dp[j] += dp[j - coins[i]];
}
}
return dp[sum];
}
int main()
{
vector<int> coins = {1, 2, 3};
int n = coins.size();
int sum = 5;
cout << count(coins, n, sum) << endl;
return 0;
}
Time complexity : O(N*sum)
Auxiliary Space : O(sum)
Explore
C++ Basics
Core Concepts
OOP in C++
Standard Template Library(STL)
Practice & Problems