给定一个大小为N的数组arr [] ,它表示可用的面额和一个整数X。任务是找到可用面额的最小硬币数量的任意组合,以使硬币的总和为X。如果无法通过可用面额获得给定的总和,请打印-1 。
例子:
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.
天真的方法:最简单的方法是尝试使用给定面额的所有可能组合,以使每种组合中的硬币总和等于X。从这些组合中,选择硬币数量最少的硬币并进行打印。如果任何组合的总和不等于X ,则打印-1 。
时间复杂度: O(X N )
辅助空间: O(N)
高效方法:可以使用动态编程来优化上述方法,以找到最小数量的硬币。在找到最小数量的硬币时,可以使用回溯来跟踪使它们的总和等于X所需的硬币。请按照以下步骤解决问题:
- 初始化辅助数组dp [] ,其中dp [i]将存储使和等于i所需的最小硬币数量。
- 使用本文讨论的方法,找到使它们的总和等于X所需的最小硬币数量。
- 找到最小数量的硬币后,使用“回溯技术”来追踪所使用的硬币,使总和等于X。
- 在回溯中,遍历数组并选择一个比当前总和小的硬币,以使dp [current_sum]等于dp [current_sum – selected_coin] +1 。将所选硬币存储在阵列中。
- 完成上述步骤后,通过将当前总和传递为(当前总和-选择的硬币值)来再次回溯。
- 找到解决方案后,打印选定硬币的阵列。
下面是上述方法的实现:
C++
// C++ program for the above approach
#include
using namespace std;
#define MAX 100000
// dp array to memoize the results
int dp[MAX + 1];
// List to store the result
list denomination;
// Function to find the minimum number of
// coins to make the sum equals to X
int countMinCoins(int n, int C[], int m)
{
// Base case
if (n == 0) {
dp[0] = 0;
return 0;
}
// If previously computed
// subproblem occurred
if (dp[n] != -1)
return dp[n];
// Initialize result
int ret = INT_MAX;
// Try every coin that has smaller
// value than n
for (int i = 0; i < m; i++) {
if (C[i] <= n) {
int x
= countMinCoins(n - C[i],
C, m);
// Check for INT_MAX to avoid
// overflow and see if result
// can be minimized
if (x != INT_MAX)
ret = min(ret, 1 + x);
}
}
// Memoizing value of current state
dp[n] = ret;
return ret;
}
// Function to find the possible
// combination of coins to make
// the sum equal to X
void findSolution(int n, int C[], int m)
{
// Base Case
if (n == 0) {
// Print Solutions
for (auto it : denomination) {
cout << it << ' ';
}
return;
}
for (int i = 0; i < m; i++) {
// Try every coin that has
// value smaller than n
if (n - C[i] >= 0
and dp[n - C[i]] + 1
== dp[n]) {
// Add current denominations
denomination.push_back(C[i]);
// Backtrack
findSolution(n - C[i], C, m);
break;
}
}
}
// Function to find the minimum
// combinations of coins for value X
void countMinCoinsUtil(int X, int C[],
int N)
{
// Initialize dp with -1
memset(dp, -1, sizeof(dp));
// Min coins
int isPossible
= countMinCoins(X, C,
N);
// If no solution exists
if (isPossible == INT_MAX) {
cout << "-1";
}
// Backtrack to find the solution
else {
findSolution(X, C, N);
}
}
// Driver code
int main()
{
int X = 21;
// Set of possible denominations
int arr[] = { 2, 3, 4, 5 };
int N = sizeof(arr) / sizeof(arr[0]);
// Function Call
countMinCoinsUtil(X, arr, N);
return 0;
}
Java
// Java program for
// the above approach
import java.util.*;
class GFG{
static final int MAX = 100000;
// dp array to memoize the results
static int []dp = new int[MAX + 1];
// List to store the result
static List denomination =
new LinkedList();
// Function to find the minimum
// number of coins to make the
// sum equals to X
static int countMinCoins(int n,
int C[], int m)
{
// Base case
if (n == 0)
{
dp[0] = 0;
return 0;
}
// If previously computed
// subproblem occurred
if (dp[n] != -1)
return dp[n];
// Initialize result
int ret = Integer.MAX_VALUE;
// Try every coin that has smaller
// value than n
for (int i = 0; i < m; i++)
{
if (C[i] <= n)
{
int x = countMinCoins(n - C[i],
C, m);
// Check for Integer.MAX_VALUE to avoid
// overflow and see if result
// can be minimized
if (x != Integer.MAX_VALUE)
ret = Math.min(ret, 1 + x);
}
}
// Memoizing value of current state
dp[n] = ret;
return ret;
}
// Function to find the possible
// combination of coins to make
// the sum equal to X
static void findSolution(int n,
int C[], int m)
{
// Base Case
if (n == 0)
{
// Print Solutions
for (int it : denomination)
{
System.out.print(it + " ");
}
return;
}
for (int i = 0; i < m; i++)
{
// Try every coin that has
// value smaller than n
if (n - C[i] >= 0 &&
dp[n - C[i]] + 1 ==
dp[n])
{
// Add current denominations
denomination.add(C[i]);
// Backtrack
findSolution(n - C[i], C, m);
break;
}
}
}
// Function to find the minimum
// combinations of coins for value X
static void countMinCoinsUtil(int X,
int C[], int N)
{
// Initialize dp with -1
for (int i = 0; i < dp.length; i++)
dp[i] = -1;
// Min coins
int isPossible = countMinCoins(X, C, N);
// If no solution exists
if (isPossible == Integer.MAX_VALUE)
{
System.out.print("-1");
}
// Backtrack to find the solution
else
{
findSolution(X, C, N);
}
}
// Driver code
public static void main(String[] args)
{
int X = 21;
// Set of possible denominations
int arr[] = {2, 3, 4, 5};
int N = arr.length;
// Function Call
countMinCoinsUtil(X, arr, N);
}
}
// This code is contributed by Rajput-Ji
Python3
# Python3 program for the above approach
import sys
MAX = 100000
# dp array to memoize the results
dp = [-1] * (MAX + 1)
# List to store the result
denomination = []
# Function to find the minimum number of
# coins to make the sum equals to X
def countMinCoins(n, C, m):
# Base case
if (n == 0):
dp[0] = 0
return 0
# If previously computed
# subproblem occurred
if (dp[n] != -1):
return dp[n]
# Initialize result
ret = sys.maxsize
# Try every coin that has smaller
# value than n
for i in range(m):
if (C[i] <= n):
x = countMinCoins(n - C[i], C, m)
# Check for INT_MAX to avoid
# overflow and see if result
#. an be minimized
if (x != sys.maxsize):
ret = min(ret, 1 + x)
# Memoizing value of current state
dp[n] = ret
return ret
# Function to find the possible
# combination of coins to make
# the sum equal to X
def findSolution(n, C, m):
# Base Case
if (n == 0):
# Print Solutions
for it in denomination:
print(it, end = " ")
return
for i in range(m):
# Try every coin that has
# value smaller than n
if (n - C[i] >= 0 and
dp[n - C[i]] + 1 == dp[n]):
# Add current denominations
denomination.append(C[i])
# Backtrack
findSolution(n - C[i], C, m)
break
# Function to find the minimum
# combinations of coins for value X
def countMinCoinsUtil(X, C,N):
# Initialize dp with -1
# memset(dp, -1, sizeof(dp))
# Min coins
isPossible = countMinCoins(X, C,N)
# If no solution exists
if (isPossible == sys.maxsize):
print("-1")
# Backtrack to find the solution
else:
findSolution(X, C, N)
# Driver code
if __name__ == '__main__':
X = 21
# Set of possible denominations
arr = [ 2, 3, 4, 5 ]
N = len(arr)
# Function call
countMinCoinsUtil(X, arr, N)
# This code is contributed by mohit kumar 29
C#
// C# program for
// the above approach
using System;
using System.Collections.Generic;
class GFG{
static readonly int MAX = 100000;
// dp array to memoize the results
static int []dp = new int[MAX + 1];
// List to store the result
static List denomination =
new List();
// Function to find the minimum
// number of coins to make the
// sum equals to X
static int countMinCoins(int n,
int []C,
int m)
{
// Base case
if (n == 0)
{
dp[0] = 0;
return 0;
}
// If previously computed
// subproblem occurred
if (dp[n] != -1)
return dp[n];
// Initialize result
int ret = int.MaxValue;
// Try every coin that has smaller
// value than n
for (int i = 0; i < m; i++)
{
if (C[i] <= n)
{
int x = countMinCoins(n - C[i],
C, m);
// Check for int.MaxValue to avoid
// overflow and see if result
// can be minimized
if (x != int.MaxValue)
ret = Math.Min(ret, 1 + x);
}
}
// Memoizing value of current state
dp[n] = ret;
return ret;
}
// Function to find the possible
// combination of coins to make
// the sum equal to X
static void findSolution(int n,
int []C,
int m)
{
// Base Case
if (n == 0)
{
// Print Solutions
foreach (int it in denomination)
{
Console.Write(it + " ");
}
return;
}
for (int i = 0; i < m; i++)
{
// Try every coin that has
// value smaller than n
if (n - C[i] >= 0 &&
dp[n - C[i]] + 1 ==
dp[n])
{
// Add current denominations
denomination.Add(C[i]);
// Backtrack
findSolution(n - C[i], C, m);
break;
}
}
}
// Function to find the minimum
// combinations of coins for value X
static void countMinCoinsUtil(int X,
int []C,
int N)
{
// Initialize dp with -1
for (int i = 0; i < dp.Length; i++)
dp[i] = -1;
// Min coins
int isPossible = countMinCoins(X, C, N);
// If no solution exists
if (isPossible == int.MaxValue)
{
Console.Write("-1");
}
// Backtrack to find the solution
else
{
findSolution(X, C, N);
}
}
// Driver code
public static void Main(String[] args)
{
int X = 21;
// Set of possible denominations
int []arr = {2, 3, 4, 5};
int N = arr.Length;
// Function Call
countMinCoinsUtil(X, arr, N);
}
}
// This code is contributed by shikhasingrajput
2 4 5 5 5
时间复杂度: O(N * X),其中N是给定数组的长度,X是给定整数。
辅助空间: O(N)