Open In App

Coin Change Problem in C++

Last Updated : 07 Aug, 2024
Comments
Improve
Suggest changes
Like Article
Like
Report

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

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-With-Recursion
Coin Change Using Recursion

Approach:

  • 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;
}

Output
 5

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;
    }
}

Output
5

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;
}

Output
5

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;
}

Output
5

Time complexity : O(N*sum)
Auxiliary Space : O(sum)


Next Article
Article Tags :
Practice Tags :

Similar Reads