Coin Change Count Ways to Make Sum (original) (raw)

Given an integer array **coins[ ] representing different denominations of currency and an integer **sum. We need tofind the number of ways we can make **sum by using different combinations from coins[ ].
**Note: Assume that we have an **infinite supply of each type of coin. Therefore, we can use any coin as many times as we want.

**Examples:

**Input: sum = 4, coins[] = [1, 2, 3]
**Output: 4
**Explanation: There are four solutions: [1, 1, 1, 1], [1, 1, 2], [2, 2] and [1, 3]

**Input: sum = 10, coins[] = [2, 5, 3, 6]
**Output: 5
**Explanation: There are five solutions:
[2, 2, 2, 2, 2], [2, 2, 3, 3], [2, 2, 6], [2, 3, 5] and [5, 5]

Table of Content

[Naive Approach] Using Recursion - O(2^sum) time and O(sum) space

To solve this problem initially, we use recursion because at every step we have a choice: either we include the current coin or we do not include it.

For each coin, there are two possibilities:

Since we are looking for all different combinations that form the given sum, the final answer will be the sum of both possibilities (include + exclude).

coin---------change_________

C++ `

//Driver Code Starts #include #include using namespace std;

//Driver Code Ends

int countRecur(vector& coins, int n, int sum) {

// If sum is 0 then there is 1 solution
if (sum == 0) return 1;

if (sum < 0 || n == 0) return 0;

// count is sum of solutions
// (i)including coins[n-1] (ii) excluding coins[n-1]
return countRecur(coins, n, sum - coins[n - 1]) + 
        countRecur(coins, n - 1, sum);

}

int count(vector &coins, int sum) { return countRecur(coins, coins.size(), sum); }

//Driver Code Starts

int main() { vector coins = {1, 2, 3}; int sum = 5; cout << count(coins, sum); return 0; }

//Driver Code Ends

Java

//Driver Code Starts import java.util.Arrays;

public class GFG {

//Driver Code Ends

static int countRecur(int[] coins, int n, int sum) {
    
    // If sum is 0 then there is 1 solution
    if (sum == 0) return 1;

    if (sum < 0 || n == 0) return 0;

    // count is sum of solutions
    // (i) including coins[n-1] (ii) excluding coins[n-1]
    return countRecur(coins, n, sum - coins[n - 1]) +
           countRecur(coins, n - 1, sum);
}

static int count(int[] coins, int sum) {
    return countRecur(coins, coins.length, sum);
}

//Driver Code Starts

public static void main(String[] args) {
    int[] coins = {1, 2, 3};
    int sum = 5;
    System.out.println(count(coins, sum));
}

}

//Driver Code Ends

Python

def countRecur(coins, n, sum):

# If sum is 0 then there is 1 solution
if sum == 0:
    return 1

if sum < 0 or n == 0:
    return 0

# count is sum of solutions
# (i) including coins[n-1] (ii) excluding coins[n-1]
return countRecur(coins, n, sum - coins[n - 1]) + \
       countRecur(coins, n - 1, sum)

def count(coins, sum): return countRecur(coins, len(coins), sum)

#Driver Code Starts

if name == "main": coins = [1, 2, 3] sum = 5 print(count(coins, sum))

#Driver Code Ends

C#

//Driver Code Starts using System;

class GFG {

//Driver Code Ends

static int countRecur(int[] coins, int n, int sum) {

    // If sum is 0 then there is 1 solution
    if (sum == 0) return 1;

    if (sum < 0 || n == 0) return 0;

    // count is sum of solutions
    // (i) including coins[n-1] (ii) excluding coins[n-1]
    return countRecur(coins, n, sum - coins[n - 1]) +
           countRecur(coins, n - 1, sum);
}

static int count(int[] coins, int sum) {
    return countRecur(coins, coins.Length, sum);
}

//Driver Code Starts

static void Main() {
    int[] coins = {1, 2, 3};
    int sum = 5;
    Console.WriteLine(count(coins, sum));
}

}

//Driver Code Ends

JavaScript

function countRecur(coins, n, sum) {

// If sum is 0 then there is 1 solution
if (sum === 0) return 1;

if (sum < 0 || n === 0) return 0;

// count is sum of solutions
// (i) including coins[n-1] (ii) excluding coins[n-1]
return countRecur(coins, n, sum - coins[n - 1]) +
       countRecur(coins, n - 1, sum);

}

function count(coins, sum) { return countRecur(coins, coins.length, sum); }

//Driver Code Starts //Driver Code let coins = [1, 2, 3]; let sum = 5; console.log(count(coins, sum));

//Driver Code Ends

`

[Expected Approach 1] Using Top-Down DP (Memoization) - O(sum*n) time and O(sum*n) space

In the previous recursive approach, we observed that many subproblems are solved repeatedly. This repetition increases time complexity. To handle this, we use Memoization.

We create a DP table of size n × (sum + 1), because the result of the recursion depends on two changing parameters: the number of coins considered and the remaining target sum So whenever we compute a subproblem count(i, sum), we store the result in the DP table. Next time when the same subproblem appears, instead of computing it again, we directly fetch it from the DP table, which saves a lot of time.

C++ `

//Driver Code Starts #include #include using namespace std;

//Driver Code Ends

int countRecur(vector& coins, int n, int sum, vector<vector> &dp) {

// If sum is 0 then there is 1 solution
if (sum == 0) return 1;

if (sum < 0 || n == 0) return 0;

// If the subproblem is previously calculated then
// simply return the result
if (dp[n-1][sum]!=-1) return dp[n-1][sum];

// count is sum of solutions (i)
// including coins[n-1] (ii) excluding coins[n-1]
return dp[n-1][sum] = 
    countRecur(coins, n, sum - coins[n-1], dp) + 
    countRecur(coins, n - 1, sum, dp);

}

int count(vector &coins, int sum) {

vector<vector<int>> dp(coins.size(), vector<int>(sum+1, -1));
return countRecur(coins, coins.size(), sum, dp);

}

//Driver Code Starts

int main() { vector coins = {1, 2, 3}; int sum = 5; cout << count(coins, sum); return 0; }

//Driver Code Ends

Java

//Driver Code Starts import java.util.Arrays;

class GFG {

//Driver Code Ends

static int countRecur(int[] coins, int n, int sum, int[][] dp) {

    // If sum is 0 then there is 1 solution
    if (sum == 0) return 1;

    if (sum < 0 || n == 0) return 0;

    // If the subproblem is previously calculated then
    // simply return the result
    if (dp[n-1][sum] != -1) return dp[n-1][sum];

    // count is sum of solutions (i)
    // including coins[n-1] (ii) excluding coins[n-1]
    return dp[n-1][sum] =
            countRecur(coins, n, sum - coins[n - 1], dp) +
            countRecur(coins, n - 1, sum, dp);
}

static int count(int[] coins, int sum) {
    int[][] dp = new int[coins.length][sum + 1];
    for (int[] row : dp) Arrays.fill(row, -1);
    return countRecur(coins, coins.length, sum, dp);
}

//Driver Code Starts

public static void main(String[] args) {
    int[] coins = {1, 2, 3};
    int sum = 5;
    System.out.println(count(coins, sum));
}

}

//Driver Code Ends

Python

def countRecur(coins, n, sum, dp):

# If sum is 0 then there is 1 solution
if sum == 0: 
    return 1

if sum < 0 or n == 0:
    return 0

# If the subproblem is previously calculated then
# simply return the result
if dp[n-1][sum] != -1:
    return dp[n-1][sum]

# count is sum of solutions (i)
# including coins[n-1] (ii) excluding coins[n-1]
dp[n-1][sum] = (
    countRecur(coins, n, sum - coins[n-1], dp) +
    countRecur(coins, n - 1, sum, dp)
)
return dp[n-1][sum]

def count(coins, sum): dp = [[-1 for _ in range(sum + 1)] for _ in range(len(coins))] return countRecur(coins, len(coins), sum, dp)

#Driver Code Starts

if name == "main": coins = [1, 2, 3] sum = 5 print(count(coins, sum))

#Driver Code Ends

C#

//Driver Code Starts using System;

class GFG { //Driver Code Ends

static int countRecur(int[] coins, int n, int sum, int[,] dp)
{
    // If sum is 0 then there is 1 solution
    if (sum == 0) return 1;

    if (sum < 0 || n == 0) return 0;

    // If the subproblem is previously calculated then
    // simply return the result
    if (dp[n - 1, sum] != -1) return dp[n - 1, sum];

    // count is sum of solutions (i)
    // including coins[n-1] (ii) excluding coins[n-1]
    dp[n - 1, sum] =
        countRecur(coins, n, sum - coins[n - 1], dp) +
        countRecur(coins, n - 1, sum, dp);

    return dp[n - 1, sum];
}

static int count(int[] coins, int sum)
{
    int[,] dp = new int[coins.Length, sum + 1];
    for (int i = 0; i < coins.Length; i++)
        for (int j = 0; j <= sum; j++)
            dp[i, j] = -1;

    return countRecur(coins, coins.Length, sum, dp);
}

//Driver Code Starts

static void Main()
{
    int[] coins = { 1, 2, 3 };
    int sum = 5;
    Console.WriteLine(count(coins, sum));
}

}

//Driver Code Ends

JavaScript

function countRecur(coins, n, sum, dp) {

// If sum is 0 then there is 1 solution
if (sum === 0) return 1;

if (sum < 0 || n === 0) return 0;

// If the subproblem is previously calculated then
// simply return the result
if (dp[n-1][sum] !== -1) return dp[n-1][sum];

// count is sum of solutions (i)
// including coins[n-1] (ii) excluding coins[n-1]
dp[n-1][sum] =
    countRecur(coins, n, sum - coins[n - 1], dp) +
    countRecur(coins, n - 1, sum, dp);

return dp[n-1][sum];

}

function count(coins, sum) { const dp = Array.from({ length: coins.length }, () => Array(sum + 1).fill(-1)); return countRecur(coins, coins.length, sum, dp); }

//Driver Code Starts //Driver Code const coins = [1, 2, 3]; const sum = 5; console.log(count(coins, sum));

//Driver Code Ends

`

[Better Approach 2] Using Bottom-Up DP (Tabulation) – O(sum*n) time and O(sum*n) space

In the memoization approach we solved each subproblem top-down using recursion, but in the tabulation approach we build the solution in a bottom-up manner by filling a DP table iteratively.

We first define the base cases for the DP table.

After the base initialization, we fill the table iteratively using the same idea.

C++ `

//Driver Code Starts #include using namespace std;

//Driver Code Ends

int count(vector& coins, int sum) { int n = coins.size();

vector<vector<int> > dp(n + 1, vector<int>(sum + 1, 0));

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 Starts

int main() { vector coins = {1, 2, 3}; int sum = 5; cout << count(coins, sum); return 0; }

//Driver Code Ends

Java

//Driver Code Starts import java.util.Arrays;

public class GFG{

//Driver Code Ends

static int count(int[] coins, int sum) {
    int n = coins.length;

    int[][] dp = new int[n + 1][sum + 1];

    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 Starts public static void main(String[] args) { int[] coins = {1, 2, 3}; int sum = 5; System.out.println(count(coins, sum)); } }

//Driver Code Ends

Python

def count(coins, sum):

n = len(coins)

# Initialize DP table
dp = [[0] * (sum + 1) for _ in range(n + 1)]

dp[0][0] = 1
for i in range(1, n + 1):
    for j in range(sum + 1):

        # 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 Starts if name == "main": coins = [1, 2, 3] sum = 5 print(count(coins, sum))

#Driver Code Ends

C#

//Driver Code Starts using System;

class GFG { //Driver Code Ends

static int count(int[] coins, int sum)
{
    int n = coins.Length;

    int[,] dp = new int[n + 1, sum + 1];

    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 Starts

static void Main()
{
    int[] coins = { 1, 2, 3 };
    int sum = 5;
    Console.WriteLine(count(coins, sum));
}

}

//Driver Code Ends

JavaScript

function count(coins, sum) {

let n = coins.length;

let dp = Array.from({length: n + 1}, () => Array(sum + 1).fill(0));

dp[0][0] = 1;

for (let i = 1; i <= n; i++) {
    for (let 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 Starts // Driver Code let coins = [1, 2, 3]; let sum = 5; console.log(count(coins, sum));

//Driver Code Ends

`

[Expected Approach] Using Space Optimized DP – O(sum*n) time and O(sum) space

In previous approach of dynamic programming we have derive the relation between states as given below:

If we observe that for calculating current dp[i][sum] state we only need previous row dp[i-1][sum] or current row dp[i][sum-coins[i]]. There is no need to store all the previous states just one previous state is used to compute result.

C++ `

//Driver Code Starts #include #include using namespace std;

//Driver Code Ends

int count(vector &coins, int sum) { int n = coins.size();

// dp[i] will be storing the number of solutions for
// value i.
vector<int> dp(sum + 1);

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

}

//Driver Code Starts

int main() { vector coins = {1, 2, 3}; int sum = 5; cout << count(coins, sum); return 0; }

//Driver Code Ends

Java

//Driver Code Starts public class GFG {

//Driver Code Ends

static int count(int[] coins, int sum) {
    int n = coins.length;
    
    // dp[i] will be storing the number of solutions for
    // value i.
    int[] dp = new int[sum + 1];
    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];
}

//Driver Code Starts

public static void main(String[] args) {
    int[] coins = {1, 2, 3};
    int sum = 5;
    System.out.println(count(coins, sum));
}

}

//Driver Code Ends

Python

def count(coins, sum): n = len(coins)

# dp[i] will be storing the number of solutions for
# value i.
dp = [0] * (sum + 1)
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 i in range(n):
    for j in range(coins[i], sum + 1):
        dp[j] += dp[j - coins[i]]

return dp[sum]

//Driver Code Starts if name == "main": coins = [1, 2, 3] sum = 5 print(count(coins, sum))

//Driver Code Ends

C#

//Driver Code Starts using System;

class GFG { //Driver Code Ends

static int count(int[] coins, int sum)
{
    int n = coins.Length;

    // dp[i] will be storing the number of solutions for
    // value i.
    int[] dp = new int[sum + 1];
    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];
}

//Driver Code Starts

static void Main()
{
    int[] coins = {1, 2, 3};
    int sum = 5;
    Console.WriteLine(count(coins, sum));
}

}

//Driver Code Ends

JavaScript

function count(coins, sum) { let n = coins.length;

// dp[i] will be storing the number of solutions for
// value i.
let dp = Array(sum + 1).fill(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 (let i = 0; i < n; i++)
    for (let j = coins[i]; j <= sum; j++)
        dp[j] += dp[j - coins[i]];

return dp[sum];

}

//Driver Code Starts // Driver Code let coins = [1, 2, 3]; let sum = 5; console.log(count(coins, sum));

//Driver Code Ends

`

**Related articles: