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)
Similar Reads
Naming Convention in C++ Naming a file or a variable is the first and the very basic step that a programmer takes to write clean codes, where naming has to be appropriate so that for any other programmer it acts as an easy way to read the code. In C++, naming conventions are the set of rules for choosing the valid name for
6 min read
OpenCV C++ Program for coin detection The following is the explanation to the C++ code for coin detection in C++ using the tool OpenCV. Things to know: The code will only compile in Linux environment. To run in windows, please use the file: 'coin.o' and run it in cmd. However if it does not run(problem in system architecture) then compi
4 min read
How to Read and Print an Integer value in C++ The given task is to take an integer as input from the user and print that integer in C++ language. In this article, we will learn how to read and print an integer value. In the below program, the syntax and procedures to take the integer as input from the user is shown in C++ language. Standard Inp
2 min read
ATM using file handling in C++ In this article, the task is to implement an ATM with functions like add, delete, search, and update users using file handling in C++. Â File handling: File handling is used to store the output of a program in a file.In C++, files use three classes fstream, ifstream, ofstream available in fstream he
6 min read
Data Races in C++ In C++, data race is a commonly occurring problem in concurrent programming. It occurs when two or more threads concurrently access the same memory location, and at least one of the accesses is a write. Data races lead to undefined behaviour, which means the program can exhibit unpredictable behavio
5 min read