Generate a combination of minimum coins that sums to a given value
Given an array arr[] of size N representing the available denominations and an integer X. The task is to find any combination of the minimum number of coins of the available denominations such that the sum of the coins is X. If the given sum cannot be obtained by the available denominations, print -1.
Examples:
Input: X = 21, arr[] = {2, 3, 4, 5}
Output: 2 4 5 5 5
Explanation:
One possible solution is {2, 4, 5, 5, 5} where 2 + 4 + 5 + 5 + 5 = 21.
Another possible solution is {3, 3, 5, 5, 5}.
Input: X = 1, arr[] = {2, 4, 6, 9}
Output: -1
Explanation:
All coins are greater than 1. Hence, no solution exist.
Naive Approach: The simplest approach is to try all possible combinations of given denominations such that in each combination, the sum of coins is equal to X. From these combinations, choose the one having the minimum number of coins and print it. If the sum any combinations is not equal to X, print -1.
Time Complexity: O(XN)
Auxiliary Space: O(N)
Efficient Approach: The above approach can be optimized using Dynamic Programming to find the minimum number of coins. While finding the minimum number of coins, backtracking can be used to track the coins needed to make their sum equals to X. Follow the below steps to solve the problem:
- Initialize an auxiliary array dp[], where dp[i] will store the minimum number of coins needed to make sum equals to i.
- Find the minimum number of coins needed to make their sum equals to X using the approach discussed in this article.
- After finding the minimum number of coins use the Backtracking Technique to track down the coins used, to make the sum equals to X.
- In backtracking, traverse the array and choose a coin which is smaller than the current sum such that dp[current_sum] equals to dp[current_sum – chosen_coin]+1. Store the chosen coin in an array.
- After completing the above step, backtrack again by passing the current sum as (current sum – chosen coin value).
- After finding the solution, print the array of chosen coins.
Below is the implementation of the above approach:
C++
#include <bits/stdc++.h>
using namespace std;
#define MAX 100000
int dp[MAX + 1];
list< int > denomination;
int countMinCoins( int n, int C[], int m)
{
if (n == 0) {
dp[0] = 0;
return 0;
}
if (dp[n] != -1)
return dp[n];
int ret = INT_MAX;
for ( int i = 0; i < m; i++) {
if (C[i] <= n) {
int x
= countMinCoins(n - C[i],
C, m);
if (x != INT_MAX)
ret = min(ret, 1 + x);
}
}
dp[n] = ret;
return ret;
}
void findSolution( int n, int C[], int m)
{
if (n == 0) {
for ( auto it : denomination) {
cout << it << ' ' ;
}
return ;
}
for ( int i = 0; i < m; i++) {
if (n - C[i] >= 0
and dp[n - C[i]] + 1
== dp[n]) {
denomination.push_back(C[i]);
findSolution(n - C[i], C, m);
break ;
}
}
}
void countMinCoinsUtil( int X, int C[],
int N)
{
memset (dp, -1, sizeof (dp));
int isPossible
= countMinCoins(X, C,
N);
if (isPossible == INT_MAX) {
cout << "-1" ;
}
else {
findSolution(X, C, N);
}
}
int main()
{
int X = 21;
int arr[] = { 2, 3, 4, 5 };
int N = sizeof (arr) / sizeof (arr[0]);
countMinCoinsUtil(X, arr, N);
return 0;
}
|
Java
import java.util.*;
class GFG{
static final int MAX = 100000 ;
static int []dp = new int [MAX + 1 ];
static List<Integer> denomination =
new LinkedList<Integer>();
static int countMinCoins( int n,
int C[], int m)
{
if (n == 0 )
{
dp[ 0 ] = 0 ;
return 0 ;
}
if (dp[n] != - 1 )
return dp[n];
int ret = Integer.MAX_VALUE;
for ( int i = 0 ; i < m; i++)
{
if (C[i] <= n)
{
int x = countMinCoins(n - C[i],
C, m);
if (x != Integer.MAX_VALUE)
ret = Math.min(ret, 1 + x);
}
}
dp[n] = ret;
return ret;
}
static void findSolution( int n,
int C[], int m)
{
if (n == 0 )
{
for ( int it : denomination)
{
System.out.print(it + " " );
}
return ;
}
for ( int i = 0 ; i < m; i++)
{
if (n - C[i] >= 0 &&
dp[n - C[i]] + 1 ==
dp[n])
{
denomination.add(C[i]);
findSolution(n - C[i], C, m);
break ;
}
}
}
static void countMinCoinsUtil( int X,
int C[], int N)
{
for ( int i = 0 ; i < dp.length; i++)
dp[i] = - 1 ;
int isPossible = countMinCoins(X, C, N);
if (isPossible == Integer.MAX_VALUE)
{
System.out.print( "-1" );
}
else
{
findSolution(X, C, N);
}
}
public static void main(String[] args)
{
int X = 21 ;
int arr[] = { 2 , 3 , 4 , 5 };
int N = arr.length;
countMinCoinsUtil(X, arr, N);
}
}
|
Python3
import sys
MAX = 100000
dp = [ - 1 ] * ( MAX + 1 )
denomination = []
def countMinCoins(n, C, m):
if (n = = 0 ):
dp[ 0 ] = 0
return 0
if (dp[n] ! = - 1 ):
return dp[n]
ret = sys.maxsize
for i in range (m):
if (C[i] < = n):
x = countMinCoins(n - C[i], C, m)
if (x ! = sys.maxsize):
ret = min (ret, 1 + x)
dp[n] = ret
return ret
def findSolution(n, C, m):
if (n = = 0 ):
for it in denomination:
print (it, end = " " )
return
for i in range (m):
if (n - C[i] > = 0 and
dp[n - C[i]] + 1 = = dp[n]):
denomination.append(C[i])
findSolution(n - C[i], C, m)
break
def countMinCoinsUtil(X, C,N):
isPossible = countMinCoins(X, C,N)
if (isPossible = = sys.maxsize):
print ( "-1" )
else :
findSolution(X, C, N)
if __name__ = = '__main__' :
X = 21
arr = [ 2 , 3 , 4 , 5 ]
N = len (arr)
countMinCoinsUtil(X, arr, N)
|
C#
using System;
using System.Collections.Generic;
class GFG{
static readonly int MAX = 100000;
static int []dp = new int [MAX + 1];
static List< int > denomination =
new List< int >();
static int countMinCoins( int n,
int []C,
int m)
{
if (n == 0)
{
dp[0] = 0;
return 0;
}
if (dp[n] != -1)
return dp[n];
int ret = int .MaxValue;
for ( int i = 0; i < m; i++)
{
if (C[i] <= n)
{
int x = countMinCoins(n - C[i],
C, m);
if (x != int .MaxValue)
ret = Math.Min(ret, 1 + x);
}
}
dp[n] = ret;
return ret;
}
static void findSolution( int n,
int []C,
int m)
{
if (n == 0)
{
foreach ( int it in denomination)
{
Console.Write(it + " " );
}
return ;
}
for ( int i = 0; i < m; i++)
{
if (n - C[i] >= 0 &&
dp[n - C[i]] + 1 ==
dp[n])
{
denomination.Add(C[i]);
findSolution(n - C[i], C, m);
break ;
}
}
}
static void countMinCoinsUtil( int X,
int []C,
int N)
{
for ( int i = 0; i < dp.Length; i++)
dp[i] = -1;
int isPossible = countMinCoins(X, C, N);
if (isPossible == int .MaxValue)
{
Console.Write( "-1" );
}
else
{
findSolution(X, C, N);
}
}
public static void Main(String[] args)
{
int X = 21;
int []arr = {2, 3, 4, 5};
int N = arr.Length;
countMinCoinsUtil(X, arr, N);
}
}
|
Javascript
<script>
var MAX = 100000;
var dp = Array(MAX+1);
var denomination = [];
function countMinCoins(n, C, m)
{
if (n == 0) {
dp[0] = 0;
return 0;
}
if (dp[n] != -1)
return dp[n];
var ret = 1000000000;
for ( var i = 0; i < m; i++) {
if (C[i] <= n) {
var x
= countMinCoins(n - C[i],
C, m);
if (x != 1000000000)
ret = Math.min(ret, 1 + x);
}
}
dp[n] = ret;
return ret;
}
function findSolution(n, C, m)
{
if (n == 0) {
denomination.forEach(it => {
document.write( it + ' ' );
});
return ;
}
for ( var i = 0; i < m; i++) {
if (n - C[i] >= 0
&& dp[n - C[i]] + 1
== dp[n]) {
denomination.push(C[i]);
findSolution(n - C[i], C, m);
break ;
}
}
}
function countMinCoinsUtil(X, C, N)
{
dp = Array(MAX+1).fill(-1);
var isPossible
= countMinCoins(X, C,
N);
if (isPossible == 1000000000) {
document.write( "-1" );
}
else {
findSolution(X, C, N);
}
}
var X = 21;
var arr = [2, 3, 4, 5];
var N = arr.length;
countMinCoinsUtil(X, arr, N);
</script>
|
Time Complexity: O(N*X), where N is the length of the given array and X is the given integer.
Auxiliary Space: O(N)
Efficient approach : Using DP Tabulation method ( Iterative approach )
The approach to solve this problem is same but DP tabulation(bottom-up) method is better then Dp + memoization(top-down) because memoization method needs extra stack space of recursion calls.
Steps to solve this problem :
- Create a array DP to store the solution of the subproblems and initialize it with INT_MAX.
- Initialize the array DP with base case i.e. dp[0] = 0 .
- Now Iterate over subproblems to get the value of current problem form previous computation of subproblems stored in DP
- Return the final solution stored in dp[X].
Implementation :
C++
#include <bits/stdc++.h>
using namespace std;
#define MAX 100000
int countMinCoins( int X, int C[], int N)
{
int dp[X + 1];
dp[0] = 0;
for ( int i = 1; i <= X; i++) {
dp[i] = INT_MAX;
}
for ( int i = 1; i <= X; i++) {
for ( int j = 0; j < N; j++) {
if (C[j] <= i && dp[i - C[j]] != INT_MAX) {
dp[i] = min(dp[i], 1 + dp[i - C[j]]);
}
}
}
if (dp[X] == INT_MAX) {
cout << "-1" ;
return -1;
}
int i = X;
while (i > 0) {
for ( int j = 0; j < N; j++) {
if (i >= C[j] && dp[i - C[j]] == dp[i] - 1) {
cout << C[j] << " " ;
i -= C[j];
break ;
}
}
}
return dp[X];
}
int main()
{
int X = 21;
int arr[] = { 2, 3, 4, 5 };
int N = sizeof (arr) / sizeof (arr[0]);
countMinCoins(X, arr, N);
return 0;
}
|
Java
import java.util.*;
public class Main {
public static int countMinCoins( int X, int [] C, int N) {
int [] dp = new int [X + 1 ];
dp[ 0 ] = 0 ;
for ( int i = 1 ; i <= X; i++) {
dp[i] = Integer.MAX_VALUE;
}
for ( int i = 1 ; i <= X; i++) {
for ( int j = 0 ; j < N; j++) {
if (C[j] <= i && dp[i - C[j]] != Integer.MAX_VALUE) {
dp[i] = Math.min(dp[i], 1 + dp[i - C[j]]);
}
}
}
if (dp[X] == Integer.MAX_VALUE) {
System.out.println( "-1" );
return - 1 ;
}
int i = X;
while (i > 0 ) {
for ( int j = 0 ; j < N; j++) {
if (i >= C[j] && dp[i - C[j]] == dp[i] - 1 ) {
System.out.print(C[j] + " " );
i -= C[j];
break ;
}
}
}
System.out.println();
return dp[X];
}
public static void main(String[] args) {
int X = 21 ;
int [] arr = { 2 , 3 , 4 , 5 };
int N = arr.length;
countMinCoins(X, arr, N);
}
}
|
Python3
import sys
def countMinCoins(X, C, N):
dp = [sys.maxsize] * (X + 1 )
dp[ 0 ] = 0
for i in range ( 1 , X + 1 ):
for j in range (N):
if C[j] < = i and dp[i - C[j]] ! = sys.maxsize:
dp[i] = min (dp[i], 1 + dp[i - C[j]])
if dp[X] = = sys.maxsize:
print ( "-1" )
return - 1
i = X
while i > 0 :
for j in range (N):
if i > = C[j] and dp[i - C[j]] = = dp[i] - 1 :
print (C[j], end = " " )
i - = C[j]
break
return dp[X]
if __name__ = = "__main__" :
X = 21
arr = [ 2 , 3 , 4 , 5 ]
N = len (arr)
countMinCoins(X, arr, N)
|
C#
using System;
class Program
{
static int CountMinCoins( int X, int [] C, int N)
{
int [] dp = new int [X + 1];
dp[0] = 0;
for ( int i = 1; i <= X; i++)
{
dp[i] = int .MaxValue;
}
for ( int i = 1; i <= X; i++)
{
for ( int j = 0; j < N; j++)
{
if (C[j] <= i && dp[i - C[j]] != int .MaxValue)
{
dp[i] = Math.Min(dp[i], 1 + dp[i - C[j]]);
}
}
}
if (dp[X] == int .MaxValue)
{
Console.WriteLine( "-1" );
return -1;
}
int k = X;
while (k > 0)
{
for ( int j = 0; j < N; j++)
{
if (k >= C[j] && dp[k - C[j]] == dp[k] - 1)
{
Console.Write(C[j] + " " );
k -= C[j];
break ;
}
}
}
return dp[X];
}
static void Main( string [] args)
{
int X = 21;
int [] arr = { 2, 3, 4, 5 };
int N = arr.Length;
CountMinCoins(X, arr, N);
}
}
|
Javascript
function countMinCoins(X, C, N) {
const dp = new Array(X + 1).fill(Infinity);
dp[0] = 0;
for (let i = 1; i <= X; i++) {
for (let j = 0; j < N; j++) {
if (C[j] <= i && dp[i - C[j]] !== Infinity) {
dp[i] = Math.min(dp[i], 1 + dp[i - C[j]]);
}
}
}
if (dp[X] === Infinity) {
console.log( "-1" );
return -1;
}
let i = X;
const result = [];
while (i > 0) {
for (let j = 0; j < N; j++) {
if (i >= C[j] && dp[i - C[j]] === dp[i] - 1) {
result.push(C[j]);
i -= C[j];
break ;
}
}
}
console.log(result.join( ' ' ));
return dp[X];
}
const X = 21;
const arr = [2, 3, 4, 5];
const N = arr.length;
countMinCoins(X, arr, N);
|
Output
2 4 5 5 5
Time Complexity: O(N*X), where N is the length of the given array and X is the given integer.
Auxiliary Space: O(X)
Last Updated :
06 Jan, 2024
Like Article
Save Article
Share your thoughts in the comments
Please Login to comment...