Algorithm 最小硬币兑换(有限供应),时间复杂度更高
这个问题需要用户返回一个最小硬币列表作为更改。例如,[.01、.10、.25]、.40。和(所有硬币都有10个供应数量)应返回[.10、.10、.10、.10],但不返回[.25、.1、.01、.01、.01、.01、.01] 贪婪的方法行不通。这个问题就是动态规划问题。所述溶液为O(2^n)。我们如何使用自底向上的方法将其优化到O(n^2)或更好Algorithm 最小硬币兑换(有限供应),时间复杂度更高,algorithm,recursion,optimization,data-structures,dynamic-programming,Algorithm,Recursion,Optimization,Data Structures,Dynamic Programming,这个问题需要用户返回一个最小硬币列表作为更改。例如,[.01、.10、.25]、.40。和(所有硬币都有10个供应数量)应返回[.10、.10、.10、.10],但不返回[.25、.1、.01、.01、.01、.01、.01] 贪婪的方法行不通。这个问题就是动态规划问题。所述溶液为O(2^n)。我们如何使用自底向上的方法将其优化到O(n^2)或更好 class CoinChange { public static List<Double> findMinRefundComb
class CoinChange {
public static List<Double> findMinRefundCombination(List<Double> inputCoins, double refundToMake) {
List<Double> minCoins = new ArrayList<>();
List<Double> coinsAccumulatedSoFar = new ArrayList<>();
double refundSoFar = 0.0d;
findMinRefundCombinationHelper(inputCoins, refundToMake, minCoins,coinsAccumulatedSoFar, 0, refundSoFar);
System.out.println(minCoins.size());
return minCoins;
}
public static void findMinRefundCombinationHelper(List<Double> inputCoins, double refundToMake, List<Double> minCoins, List<Double> coinsAccumulatedSoFar, int curIndex, double refundSoFar) {
if(refundSoFar > refundToMake || curIndex == inputCoins.size()) {
return;
}
if(refundSoFar == refundToMake) {
if(minCoins.isEmpty()) {
for(Double coin: coinsAccumulatedSoFar)
minCoins.add(coin);
} else {
if(coinsAccumulatedSoFar.size() < minCoins.size()) {
minCoins.clear();
for(Double coin: coinsAccumulatedSoFar)
minCoins.add(coin);
}
}
}
coinsAccumulatedSoFar.add(inputCoins.get(curIndex));
// findMinRefundCombinationHelper(inputCoins, refundToMake, minCoins, coinsAccumulatedSoFar,curIndex,refundSoFar + inputCoins.get(curIndex));
findMinRefundCombinationHelper(inputCoins, refundToMake, minCoins, coinsAccumulatedSoFar, curIndex + 1, refundSoFar + inputCoins.get(curIndex));
coinsAccumulatedSoFar.remove(coinsAccumulatedSoFar.size() - 1);
findMinRefundCombinationHelper(inputCoins, refundToMake, minCoins, coinsAccumulatedSoFar, curIndex + 1, refundSoFar);
}
public static void main(String[] args) {
List<Double> inputCoins = new ArrayList<>();
inputCoins.add(.01);
// inputCoins.add();
inputCoins.add(.10);
inputCoins.add(.25);
inputCoins.add(0.50);
inputCoins.add(1.0);
double refundToMake = 0.40;
List<Double> minCoins = findMinRefundCombination(inputCoins, refundToMake);
for(Double coin: minCoins)
System.out.print(coin + " ");
System.out.println();
}
}
阶级变革{
公共静态列表findMinRefundCombination(列表输入硬币,双倍退款){
List minCoins=new ArrayList();
List coinsAccumulatedSoFar=new ArrayList();
双倍退款截止日期=0.0d;
findMinRefundCombinationHelper(输入硬币、退款制造、minCoins、硬币累计金额、0、退款金额);
System.out.println(minCoins.size());
归还硬币;
}
public static void findMinRefundCombinationHelper(列出inputCoins、double ReturnToMake、List minCoins、List Coins累计金额、int curIndex、double ReturnsFar){
if(refundSoFar>refundToMake | | curIndex==inputCoins.size()){
回来
}
如果(退款金额==退款金额){
if(minCoins.isEmpty()){
用于(双币:累积到目前为止的硬币)
minCoins.add(硬币);
}否则{
如果(硬币累计到当前大小()
如果您试图表示的金额足够低,则此问题可以转化为背包的变化
在注释中,您声明所有数字的精度为小数点后两位,因此所有数字都可以通过乘以100转换为整数。让我们也从原始输入中给出的每个硬币中创建10个硬币,并声明我们最多可以使用每个新硬币一次
这里的想法类似于背包:让我们引入一个函数F(k,i)
,它表示如果我们只使用一些前i
硬币,我们需要多少硬币才能获得sumk
。例如,F(0,i)
是0,因为对于我们可用的任何硬币子集,我们都可以不使用它们来实现和0F(k>0,0)
是未定义的,因为我们无法在不使用硬币的情况下获得大于0的总和,F(|第一枚硬币的值|,1)
等于1。请注意,F(k,10N)
将是问题的答案
这里的循环关系是
F(k,i)=min(F(k,i-1),F(k-|硬币i |,i-1的值))
对于k,i
的适用值。在英语中,我们说“要么我们使用第i个硬币,在这种情况下,总和必须增加其值,要么我们没有增加”。数字可以有多少位精度?精度是小数点后2位,最多0.01如果每个硬币的数量不限,则dp代表每个可能的值,跟踪生成该值所需的最少硬币数量。dp[i]=min(dp[i-0.01],dp[i-0.1],dp[i-0.25],dp[i-0.4])+1。如果该值处的dp不为null,则缺少一些要处理的if,但这就是问题所在。不确定如何限制10枚硬币的使用您是否建议自下而上的方法?这里的时间复杂性是什么?O(N^3)?在这种情况下,不管你是自下而上还是自上而下。时间复杂度不能仅用N来表示——您试图改变的值也很重要。放弃100的乘法,从每一个硬币中创造10个硬币(因为这些是常数),我们看的是O(K*N)算法的复杂性。这是NP难吗?不仅是NP难,也是NP完全的。