找到所需的最少数量的硬币,可以从1到99美分进行任何更改

时间:2010-10-16 06:04:11

标签: performance algorithm

最近,我挑战我的同事写一个算法来解决这个问题:

  

找到所需的最少数量的硬币,可以从1到99美分进行任何更改。硬币只能是硬币(1),镍币(5),硬币(10)和四分之一(25),你必须能够使用这些硬币从1到99(以1美分为增量)制作每个值。

然而,我意识到我实际上并不知道如何在不检查每种可能的硬币组合的情况下做到这一点。必须有一种更好的方法来解决这个问题,但我不知道这种类型的算法的通用名称会被调用,除了查看每个解决方案之外,我无法找到简化它的方法。 / p>

我想知道是否有人能指出我正确的方向,或提供更有效的算法。

28 个答案:

答案 0 :(得分:23)

您正在寻找的是动态编程

您实际上不必为每个可能的值枚举所有可能的组合,因为您可以在之前的答案之上构建它。

您的算法需要采用2个参数:

  • 可能的硬币值列表,此处为[1, 5, 10, 25]
  • 要涵盖的范围,[1, 99]

目标是计算此范围所需的最小硬币集。

最简单的方法是以自下而上的方式进行:

Range     Number of coins (in the minimal set)
          1   5   10   25
[1,1]     1
[1,2]     2
[1,3]     3
[1,4]     4
[1,5]     5
[1,5]*    4   1             * two solutions here
[1,6]     4   1
[1,9]     4   1
[1,10]    5   1             * experience tells us it's not the most viable one :p
[1,10]    4   2             * not so viable either
[1,10]    4   1   1
[1,11]    4   1   1
[1,19]    4   1   1
[1,20]    5   1   1         * not viable (in the long run)
[1,20]    4   2   1         * not viable (in the long run)
[1,20]    4   1   2

这有点容易,在每一步我们都可以通过添加至多一枚硬币,我们只需要知道在哪里。归结为范围[x,y]包含在[x,y+1]中,因此[x,y+1]的最小集应包含[x,y]的最小集。

正如您可能已经注意到的那样,有时会有犹豫不决,即多组具有相同数量的硬币。在这种情况下,只能稍后决定应丢弃哪一个。

我认为应该可以改善其运行时间,当我注意到添加硬币时通常会让你覆盖你添加硬币的范围更大的范围。

例如,请注意:

 [1,5]    4*1  1*5
 [1,9]    4*1  1*5

我们添加了一个镍来覆盖[1,5],但这样我们可以免费获得[1,9]

但是,在处理令人遗憾的输入集[2,3,5,10,25]以涵盖[2,99]时,我不确定如何快速检查新集合涵盖的范围,或者实际上它会更有效。

答案 1 :(得分:9)

您可以很快找到上限。

说,你需要四分之三。然后你只需用其他硬币填补“空白”1-24,26-49,51-74,76-99。

平凡地说,这将适用于2角钱,1个镍币和4个便士。

所以,3 + 4 + 2 + 1应该是你的硬币数量的上限。每当你的蛮力算法超过thta时,你可以立即停止搜索更深层。

对于动态编程,搜索的其余部分应该足够快地用于任何目的。

(编辑:根据Gabe的观察确定答案)

答案 2 :(得分:7)

你需要至少4便士,因为你希望得到4作为改变,你只能用便士做到这一点。

超过4便士不是最佳选择。而不是4 + x便士,你可以有4个便士和x个镍 - 它们至少跨越相同的范围。

所以你只有4便士。

您需要至少1个镍,因为您希望获得5作为更改。

含镍超过1是不理想的。而不是1 + x镍,你可以有1个镍和x硬币 - 它们至少跨越相同的范围。

所以你只有1个镍。

你需要至少2角钱,因为你想获得20分。

这意味着你有4便士,1镍和至少2角钱。

如果您的硬币少于10个,那么您将少于3个季度。但是,使用所有硬币可能获得的最大可能变化是4 + 5 + 20 + 50 = 79,还不够。

这意味着你至少有10个硬币。 Thomas's answer表明,如果你有4便士,1个镍,2个角钱和3个季度,一切都很好。

答案 3 :(得分:7)

我今天一直在学习dynamic programming,结果如下:

coins = [1,5,10,25]
d = {} # stores tuples of the form (# of coins, [coin list])

# finds the minimum # of coins needed to
# make change for some number of cents
def m(cents):
    if cents in d.keys():
        return d[cents]
    elif cents > 0:
        choices = [(m(cents - x)[0] + 1, m(cents - x)[1] + [x]) for x in coins if cents >= x]

        # given a list of tuples, python's min function
        # uses the first element of each tuple for comparison
        d[cents] = min(choices)
        return d[cents]
    else:
        d[0] = (0, [])
        return d[0]

for x in range(1, 100):
    val = m(x)
    print x, "cents requires", val[0], "coins:", val[1]

动态编程确实很神奇。

答案 4 :(得分:4)

好问题。这是我提出的逻辑。测试了几个场景,包括25.

class Program
{

    //Allowable denominations
    const int penny = 1;
    const int nickel = 5;
    const int dime = 10;
    const int quarter = 25;

    const int maxCurrencyLevelForTest =55; //1-n where n<=99

    static void Main(string[] args)
    {         
        int minPenniesNeeded = 0;
        int minNickelsNeeded = 0; 
        int minDimesNeeded = 0; 
        int minQuartersNeeded = 0;


        if (maxCurrencyLevelForTest == penny)
        {
            minPenniesNeeded = 1;
        }
        else if (maxCurrencyLevelForTest < nickel)
        {
            minPenniesNeeded = MinCountNeeded(penny, maxCurrencyLevelForTest);                
        }
        else if (maxCurrencyLevelForTest < dime)
        {
            minPenniesNeeded = MinCountNeeded(penny, nickel - 1);
            minNickelsNeeded = MinCountNeeded(nickel, maxCurrencyLevelForTest);                
        }
        else if (maxCurrencyLevelForTest < quarter)
        {
            minPenniesNeeded = MinCountNeeded(penny, nickel - 1);
            minNickelsNeeded = MinCountNeeded(nickel, dime - 1);
            minDimesNeeded = MinCountNeeded(dime, maxCurrencyLevelForTest);
        }
        else
        {
            minPenniesNeeded = MinCountNeeded(penny, nickel - 1);
            minNickelsNeeded = MinCountNeeded(nickel, dime - 1);
            minDimesNeeded = MinCountNeeded(dime, quarter - 1);

            var maxPossilbleValueWithoutQuarters = (minPenniesNeeded * penny + minNickelsNeeded * nickel + minDimesNeeded * dime);
            if (maxCurrencyLevelForTest > maxPossilbleValueWithoutQuarters)
            {               
                minQuartersNeeded = (((maxCurrencyLevelForTest - maxPossilbleValueWithoutQuarters)-1) / quarter) + 1;
            }
        }


        var minCoinsNeeded = minPenniesNeeded + minNickelsNeeded+minDimesNeeded+minQuartersNeeded;

        Console.WriteLine(String.Format("Min Number of coins needed: {0}", minCoinsNeeded));
        Console.WriteLine(String.Format("Penny: {0} needed", minPenniesNeeded));
        Console.WriteLine(String.Format("Nickels: {0} needed", minNickelsNeeded));
        Console.WriteLine(String.Format("Dimes: {0} needed", minDimesNeeded));
        Console.WriteLine(String.Format("Quarters: {0} needed", minQuartersNeeded));
        Console.ReadLine();
    }

    private static int MinCountNeeded(int denomination, int upperRange)
    {
        int remainder;
        return System.Math.DivRem(upperRange, denomination,out remainder);
    }
}

一些结果: 当maxCurrencyLevelForTest = 25

Min Number of coins needed: 7
Penny: 4 needed
Nickels: 1 needed
Dimes: 2 needed
Quarters: 0 needed

当maxCurrencyLevelForTest = 99

Min Number of coins needed: 10
Penny: 4 needed
Nickels: 1 needed
Dimes: 2 needed
Quarters: 3 needed

maxCurrencyLevelForTest:54

Min Number of coins needed: 8
Penny: 4 needed
Nickels: 1 needed
Dimes: 2 needed
Quarters: 1 needed

maxCurrencyLevelForTest:55

Min Number of coins needed: 9
Penny: 4 needed
Nickels: 1 needed
Dimes: 2 needed
Quarters: 2 needed

maxCurrencyLevelForTest:79

Min Number of coins needed: 9
Penny: 4 needed
Nickels: 1 needed
Dimes: 2 needed
Quarters: 2 needed

maxCurrencyLevelForTest:85

Min Number of coins needed: 10
Penny: 4 needed
Nickels: 1 needed
Dimes: 2 needed
Quarters: 3 needed

我猜这段代码可以进一步重构。

答案 5 :(得分:3)

编辑:正如评论者所说,我误解了这个问题。 (问题非常类似于基本的CS问题,我看到学院的学生必须解决...)挥手这不是你要找的答案。也就是说,虽然最初的答案是错误的,但我们可以将其作为O( n )解决方案的垫脚石。

所以,请在下面给出错误的答案,该答案仅解决单个值(即68美分所需的最低硬币值),并为每个值运行它。

changes = []
for amount in xrange(1, 100): # [1, 99]
    changes.append( run_the_algo_below( amount ) )
# Take the maximum for each coin type.
# ie, if run_the_algo_below returns (q, d, n, p):
change = [0, 0, 0, 0]
for c in changes:
    change = [max(c[i], change[i] for i in xrange(0, 4)]

现在,这肯定会给你一个有效的答案,但这是一个最小的答案吗? (这是更难的部分。目前我的直觉是肯定的,但我还在考虑这个......)


错误答案

哇。循环?动态编程?真的好吗?

在Python中:

amount = ( your_amount_in_cents )

quarters = amount // 25
dimes = amount % 25 // 10
nickels = amount % 25 % 10 // 5
pennies = amount % 25 % 10 % 5

可能会简化其中一些模运算...

这并不难,你只需要思考如何在现实生活中做出改变。你给出宿舍,直到添加另一个季度会让你超过所需的金额,你给出一角钱,直到添加另一个角钱会让你超过所需的金额,等等。然后,转换为数学运算:modulo和division。相同的解决方案适用于美元,将秒转换为HH:MM:SS等。

答案 6 :(得分:2)

假设你在谈论美国货币,你会想要一个贪心算法:http://en.wikipedia.org/wiki/Greedy_algorithm

从本质上讲,你尝试从最高到最低的所有面额,从每个面币中获取尽可能多的硬币,直到你什么也没有留下。

对于一般情况,请参阅http://en.wikipedia.org/wiki/Change-making_problem,因为您希望使用动态编程或线性编程来查找贪婪算法不起作用的任意面额的答案。

答案 7 :(得分:2)

在PHP中找不到这种类型问题的良好解决方案后,我开发了这个功能。

它需要任何金额(最高$ 999.99)并返回达到该值所需的每个账单/硬币的最小数量的数组。

它首先将该值转换为便士中的int(由于某种原因,当使用标准浮点值时,我会在最后得到错误)。

返还的面额也是便士(即:5000 = 50美元,100 = 1美元等)。

function makeChange($val)
{
    $amountOfMoney = intval($val*100);
    $cashInPennies = array(10000,5000,2000,1000,500,100,25,10,5,1);
    $outputArray = array();
    $currentSum = 0;
    $currentDenom = 0;

    while ($currentSum < $amountOfMoney) {
        if( ( $currentSum + $cashInPennies[$currentDenom] ) <= $amountOfMoney  ) {
            $currentSum = $currentSum + $cashInPennies[$currentDenom];
            $outputArray[$cashInPennies[$currentDenom]]++;
        } else {
            $currentDenom++;
        }
    }

    return $outputArray;

}

$change = 56.93;
$output = makeChange($change);

print_r($output);
echo "<br>Total number of bills & coins: ".array_sum($output);

=== OUTPUT ===

Array ( [5000] => 1 [500] => 1 [100] => 1 [25] => 3 [10] => 1 [5] => 1 [1] => 3 ) 
Total number of bills & coins: 11

答案 8 :(得分:1)

可能是C#

中的通用解决方案
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace CoinProblem
{
    class Program
    {
        static void Main(string[] args)
        {
            var coins = new int[] { 1, 5, 10, 25 }; // sorted lowest to highest
            int upperBound = 99;
            int numCoinsRequired = upperBound / coins.Last();
            for (int i = coins.Length - 1; i > 0; --i)
            {
                numCoinsRequired += coins[i] / coins[i - 1] - (coins[i] % coins[i - 1] == 0 ? 1 : 0);
            }
            Console.WriteLine(numCoinsRequired);
            Console.ReadLine();
        }
    }
}

我还没有完全考虑过......现在已经太晚了。在这种情况下,我认为答案应该是9,但Gabe说它应该是10 ......这就是它的收益。我想这取决于你如何解释这个问题......我们是在寻找可以产生任何价值的最小数量的硬币&lt; = X,或者可以产生任何价值的最少数量的硬币&lt; = X使用最少数量硬币?例如......我很确定我们可以只用9枚硬币制作任何价值,没有镍币,但随后生产9枚......你需要......哦......我明白了。你需要9便士,这是你没有的,因为那不是我们选择的......在 的情况下,我认为这个答案是对的。只是托马斯的想法的递归实现,但我不知道为什么他停在那里..你不需要暴力任何东西。

编辑:这是错误的。

答案 9 :(得分:1)

任务

Find the least number of coins required, that can make any change from 1 to 99 cent.

与任务不同

For each single change from 1 to 99 cent, find the least number of coins required.

因为解决方案可能是完全不同的多重硬币。

假设您没有(1),(5),(10)和(25)分硬币,但(1),(3),(5)和(17) 分硬币:要改变5,你只需要一(5)枚硬币;但是对于从1到5的所有变化,你需要两(1)个硬币和一(3)个硬币,而不是任何(5)硬币。

贪婪算法从最小值迭代到最大值,涉及变化值和硬币值:

With 1x(1) you get all change values below 2.

To make a change of 2, you need an additional coin,
which could have any value up to 2;
choose greedy -> choose the largest -> (1).

With 2x(1) you get all change values below 3.

To make a change of 3, you need an additional coin,
which could have any value up to 3;
choose greedy -> choose the largest -> (3).

With 2x(1)+1x(3) you get all change values below 6.

To make a change of 6, you need an additional coin,
which could have any value up to 6;
choose greedy -> choose the largest -> (5).

and so on...

那是在Haskell:

coinsforchange [1,3,5,17] 99
where
    coinsforchange coins change = 
        let f (coinssofar::[Int],sumsofar::Int) (largestcoin::Int,wanttogoto::Int) = 
                let coincount=(max 0 (wanttogoto-sumsofar+largestcoin-1))`div`largestcoin
                 in (replicate coincount largestcoin++coinssofar,sumsofar+coincount*largestcoin)
         in foldl f ([],0) $ zip coins $ tail [c-1|c<-coins] ++ [change]

在C ++中:

void f(std::map<unsigned,int> &coinssofar,int &sumsofar, unsigned largestcoin, int wanttogoto)
{
    int x = wanttogoto - sumsofar + largestcoin - 1;
    coinssofar[largestcoin] = (x>0) ? (x / largestcoin) : 0;
    //returns coinssofar and sumsofar;
}
std::map<unsigned,int> coinsforchange(const std::list<unsigned> &coins, int change)
{
    std::map<unsigned,int> coinssofar;
    int sumsofar=0;
    std::list<unsigned>::const_iterator coin = coins.begin();
    unsigned largestcoin = *coin;
    for( ++coin ; coin!=coins.end() ; largestcoin=*(coin++))
        f(coinssofar,sumsofar,largestcoin,(*coin) - 1);
    f(coinssofar,sumsofar,largestcoin,change);
    return coinssofar;
}

答案 10 :(得分:0)

这是我的看法。 一个有趣的事情是我们需要检查所需的最小硬币,以形成coin_with_max_value(在我们的例子中为25) - 仅限1。 之后,只计算这些最小硬币的总和。 从那时起,我们只需要添加一定数量的coin_with_max_value,以形成总成本之前的任何数字,具体取决于总成本和发现的总和的差异。就是这样。

因此,对于我们所采取的价值,一旦找到24分钟的硬币:[1,2,2,5,10,10]。 我们只需要为超过30(最小硬币总和)的每25个值添加25个硬币。 99的最终答案是:
[1,2,2,5,10,10,25,25,25]
9

import itertools
import math


def ByCurrentCoins(val, coins):
  for i in range(1, len(coins) + 1):
    combinations = itertools.combinations(coins, i)
    for combination in combinations:
      if sum(combination) == val:
        return True

  return False

def ExtraCoin(val, all_coins, curr_coins):
  for c in all_coins:
    if ByCurrentCoins(val, curr_coins + [c]):
      return c

def main():
  cost = 99
  coins = sorted([1, 2, 5, 10, 25], reverse=True)
  max_coin = coins[0]

  curr_coins = []
  for c in range(1, min(max_coin, cost+1)):
    if ByCurrentCoins(c, curr_coins):
      continue

    extra_coin = ExtraCoin(c, coins, curr_coins)
    if not extra_coin:
      print -1
      return

    curr_coins.append(extra_coin)

  curr_sum = sum(curr_coins)
  if cost > curr_sum:
    extra_max_coins = int(math.ceil((cost - curr_sum)/float(max_coin)))
    curr_coins.extend([max_coin for _ in range(extra_max_coins)])

  print curr_coins
  print len(curr_coins)

答案 11 :(得分:0)

在 node.js 中

const calculateChange = (moneyIn, cost) => {
  const change = moneyIn - cost;
  const dollars = Math.floor(change);
  let remaining = change - dollars;
  const fifty_cents = remaining / 0.5;
  const fifty_cent_coins = Math.floor(fifty_cents);
  remaining = remaining - fifty_cent_coins * 0.5;
  const twenty_five_cents = remaining / 0.25;
  const twenty_five_cent_coins = Math.floor(twenty_five_cents);
  remaining = remaining - twenty_five_cent_coins * 0.25;
  const ten_cents = remaining / 0.1;
  const ten_cent_coins = Math.floor(ten_cents);
  remaining = remaining - ten_cent_coins * 0.1;
  const five_cents = remaining / 0.05;
  const five_cent_coins = Math.floor(five_cents);
  remaining = remaining - five_cent_coins * 0.05;
  const one_cents = remaining / 0.01;
  const one_cent_coins = Math.floor(one_cents);

  return [
    one_cent_coins,
    five_cent_coins,
    ten_cent_coins,
    twenty_five_cent_coins,
    fifty_cent_coins,
    dollars,
  ];
};
const change = calculateChange(3.14, 1.99);
console.log(change)

答案 12 :(得分:0)

示例程序:

#include<stdio.h> 

    #define LEN 9 // array length
    int main(){
        int coins[LEN]={0,0,0,0,0,0,0,0,0}; // coin count
        int cointypes[LEN]={1000,500,100,50,20,10,5,2,1}; // declare your coins and note here {ASC order}   
        int sum =0; //temp variable for sum
        int inc=0; // for loop
        int amount=0; // for total amount
        printf("Enter Amount :");
        scanf("%d",&amount);
        while(sum<amount){
            if((sum+cointypes[inc])<=amount){
                   sum = sum+  cointypes[inc];
                    //printf("%d[1] - %d\n",cointypes[inc],sum);
                    //switch case to count number of notes and coin
                   switch(cointypes[inc]){
                    case 1000:
                           coins[0]++;
                           break;
                    case 500:
                           coins[1]++;
                           break;
                    case 100:
                           coins[2]++;
                           break;
                    case 50:
                           coins[3]++;
                           break;               
                    case 20:
                           coins[4]++; 
                           break;
                    case 10:
                           coins[5]++;
                           break;
                    case 5:
                           coins[6]++;
                           break;
                    case 2:
                           coins[7]++;
                           break;
                    case 1:
                           coins[8]++;
                           break;
                       }
                }else{
                   inc++;
                }
            }
        printf("note for %d in\n note 1000 * %d\n note 500 * %d\n note 100 * %d\n note 50 * %d\n note 20 * %d\n note 10 * %d\n coin 5 * %d\n coin 2 * %d\n coin 1 * %d\n",amount,coins[0],coins[1],coins[2],coins[3],coins[4],coins[5],coins[6],coins[7],coins[8]); 

    }

答案 13 :(得分:0)

java中贪婪方法的解决方案如下:

public class CoinChange {
    public static void main(String args[]) {
        int denominations[] = {1, 5, 10, 25};
        System.out.println("Total required coins are " + greeadApproach(53, denominations));
    }

    public static int greeadApproach(int amount, int denominations[]) {
        int cnt[] = new int[denominations.length];
        for (int i = denominations.length-1; amount > 0 && i >= 0; i--) {
            cnt[i] = (amount/denominations[i]);
            amount -= cnt[i] * denominations[i];            
        }
        int noOfCoins = 0;
        for (int cntVal : cnt) {
            noOfCoins+= cntVal;
        }
        return noOfCoins;
    }
}

但这适用于单一金额。如果你想在范围内运行它,那么我们必须为每个范围调用它。

答案 14 :(得分:0)

这是使用Linq的简单c#解决方案。

internal class Program
{
    public static IEnumerable<Coin> Coins = new List<Coin>
    {
        new Coin {Name = "Dime", Value = 10},
        new Coin {Name = "Penny", Value = 1},
        new Coin {Name = "Nickel", Value = 5},
        new Coin {Name = "Quarter", Value = 25}
    };
    private static void Main(string[] args)
    {
        PrintChange(34);
        Console.ReadKey();
    }
    public static void PrintChange(int amount)
    {
        decimal remaining = amount;
        //Order coins by value in descending order
        var coinsDescending = Coins.OrderByDescending(v => v.Value);
        foreach (var coin in coinsDescending)
        {
            //Continue to smaller coin when current is larger than remainder
            if (remaining < coin.Value) continue;
            // Get # of coins that fit in remaining amount
            var quotient = (int)(remaining / coin.Value);

            Console.WriteLine(new string('-',28));
            Console.WriteLine("{0,10}{1,15}", coin.Name, quotient);
            //Subtract fitting coins from remaining amount
            remaining -= quotient * coin.Value;
            if (remaining <= 0) break; //Exit when no remainder left
        }
        Console.WriteLine(new string('-', 28));
    }
    public class Coin
    {
        public string Name { get; set; }
        public int Value { get; set; }
    }
}    

答案 15 :(得分:0)

灵感来自https://www.youtube.com/watch?v=GafjS0FfAC0 以下
1)最优子问题 2)重叠子问题原则 在视频中介绍

using System;
using System.Collections.Generic;
using System.Linq;

namespace UnitTests.moneyChange
{
    public class MoneyChangeCalc
    {
        private static int[] _coinTypes;

        private Dictionary<int, int> _solutions;

        public MoneyChangeCalc(int[] coinTypes)
        {
            _coinTypes = coinTypes;
            Reset();
        }

        public int Minimun(int amount)
        {
            for (int i = 2; i <= amount; i++)
            {
                IList<int> candidates = FulfillCandidates(i);

                try
                {
                    _solutions.Add(i, candidates.Any() ? (candidates.Min() + 1) : 0);
                }
                catch (ArgumentException)
                {
                    Console.WriteLine("key [{0}] = {1} already added", i, _solutions[i]);
                }
            }

            int minimun2;
            _solutions.TryGetValue(amount, out minimun2);

            return minimun2;
        }

        internal IList<int> FulfillCandidates(int amount)
        {
            IList<int> candidates = new List<int>(3);
            foreach (int coinType in _coinTypes)
            {
                int sub = amount - coinType;
                if (sub < 0) continue;

                int candidate;
                if (_solutions.TryGetValue(sub, out candidate))
                    candidates.Add(candidate);
            }
            return candidates;
        }

        private void Reset()
        {
            _solutions = new Dictionary<int, int>
                {
                    {0,0}, {_coinTypes[0] ,1}
                };
        }
    }
}

测试用例:

using NUnit.Framework;
using System.Collections;

namespace UnitTests.moneyChange
{
    [TestFixture]
    public class MoneyChangeTest
    {
        [TestCaseSource("TestCasesData")]
        public int Test_minimun2(int amount, int[] coinTypes)
        {
            var moneyChangeCalc = new MoneyChangeCalc(coinTypes);
            return moneyChangeCalc.Minimun(amount);
        }

        private static IEnumerable TestCasesData
        {
            get
            {
                yield return new TestCaseData(6, new[] { 1, 3, 4 }).Returns(2);
                yield return new TestCaseData(3, new[] { 2, 4, 6 }).Returns(0);
                yield return new TestCaseData(10, new[] { 1, 3, 4 }).Returns(3);
                yield return new TestCaseData(100, new[] { 1, 5, 10, 20 }).Returns(5);
            }
        }
    }
}

答案 16 :(得分:0)

有几个类似的答案,但我的Java解决方案似乎更容易理解。看看这个。

public static int findMinimumNumberOfCoins(int inputCents) {

     // Error Check, If the input is 0 or lower, return 0.
     if(inputCents <= 0) return 0;

     // Create the List of Coins that We need to loop through. Start from highest to lowewst.
     // 25-10-5-1
     int[] mCoinsArray = getCoinsArray();

     // Number of Total Coins.
     int totalNumberOfCoins = 0;

     for(int i=0; i < mCoinsArray.length; i++) {

         // Get the Coin from Array.
         int coin = mCoinsArray[i];

         // If there is no inputCoin Left, simply break the for-loop
         if(inputCents == 0) break;

         // Check If we have a smaller input than our coin
         // If it's, we need to go the Next one in our Coins Array.
         // e.g, if we have 8, but the current index of array is 10, we need to go to 5.
         if(inputCents < coin) continue;

         int quotient = inputCents/coin;
         int remainder = inputCents%coin;

         // Add qutient to number of total coins.
         totalNumberOfCoins += quotient;

         // Update the input with Remainder.
         inputCents = remainder;
     }

     return totalNumberOfCoins;
 }

 // Create a Coins Array, from 25 to 1. Highest is first.
 public static int[] getCoinsArray() {

     int[] mCoinsArray = new int[4];
     mCoinsArray[0] = 25;
     mCoinsArray[1] = 10;
     mCoinsArray[2] = 5;
     mCoinsArray[3] = 1;

     return mCoinsArray;
 }

答案 17 :(得分:0)

这是c#中的代码,用于找到解决方案。

public struct CoinCount
{
    public int coinValue;
    public int noOfCoins;
}

/// <summary>
/// Find and returns the no of coins in each coins in coinSet
/// </summary>
/// <param name="coinSet">sorted coins value in assending order</param>
/// <returns></returns>
public CoinCount[] FindCoinsCountFor1to99Collection(int[] coinSet)
{
    // Add extra coin value 100 in the coin set. Since it need to find the collection upto 99.
    CoinCount[] result = new CoinCount[coinSet.Length];
    List<int> coinValues = new List<int>();
    coinValues.AddRange(coinSet);
    coinValues.Add(100);

    // Selected coin total values
    int totalCount = 0;
    for (int i = 0; i < coinValues.Count - 1; i++)
    {
        int count = 0;
        if (totalCount <= coinValues[i])
        {
            // Find the coins count
            int remainValue = coinValues[i + 1] - totalCount;
            count = (int)Math.Ceiling((remainValue * 1.0) / coinValues[i]);
        }
        else
        {
            if (totalCount <= coinValues[i + 1])
                count = 1;
            else
                count = 0;
        }
        result[i] = new CoinCount() { coinValue =  coinValues[i], noOfCoins = count };
        totalCount += coinValues[i] * count;
    }
    return result;
}

答案 18 :(得分:0)

据我了解,如果您使用的是标准货币系统值,那么只需一个循环即可轻松计算最小数量的硬币。只需总是消耗最大硬币值,如果不能检查下一个选项。但是,如果你有一个类似你有1,2,3,4等硬币的系统那么它就不起作用了。我猜硬币为1,2,5,10,25的整个想法是让人类容易计算。

答案 19 :(得分:0)

今天遇到这个,同时研究https://www.coursera.org/course/bioinformatics

DPCHANGE(money, coins)
 MinNumCoins(0) ← 0
 for m ← 1 to money
        MinNumCoins(m) ← ∞
        for i ← 1 to |coins|
            if m ≥ coini
                if MinNumCoins(m - coini) + 1 < MinNumCoins(m)
                    MinNumCoins(m) ← MinNumCoins(m - coini) + 1
    output MinNumCoins(money)

以逗号分隔的可用面值字符串和目标金额为准。

C#实施:

    public static void DPCHANGE(int val, string denoms)
    {
        int[] idenoms = Array.ConvertAll(denoms.Split(','), int.Parse);
        Array.Sort(idenoms);
        int[] minNumCoins = new int[val + 1];

        minNumCoins[0] = 0;
        for (int m = 1; m <= val; m++)
        {
            minNumCoins[m] = Int32.MaxValue - 1;
            for (int i = 1; i <= idenoms.Count() - 1; i++)
            {
                if (m >= idenoms[i])
                {
                    if (minNumCoins[m - idenoms[i]] + 1 < minNumCoins[m])
                    {
                        minNumCoins[m] = minNumCoins[m - idenoms[i]] + 1;
                    }
                }
            }
        }
    }

答案 20 :(得分:0)

对于这个问题,贪婪方法提供了比DP或其他方法更好的解决方案。 贪婪的方法:找到小于所需值的最大面额,并将其添加到要交付的硬币集中。通过刚刚添加的面额降低所需的美分,并重复直到所需的美分变为零。

我的解决方案(贪婪的方法)在java解决方案中:

public class MinimumCoinDenomination {

    private static final int[] coinsDenominations = {1, 5, 10, 25, 50, 100};

    public static Map<Integer, Integer> giveCoins(int requiredCents) {
        if(requiredCents <= 0) {
            return null;
        }
        Map<Integer, Integer> denominations = new HashMap<Integer, Integer>();

        int dollar = requiredCents/100;
        if(dollar>0) {
            denominations.put(100, dollar);
        }
        requiredCents = requiredCents - (dollar * 100);

        //int sum = 0;
        while(requiredCents > 0) {
            for(int i = 1; i<coinsDenominations.length; i++) {
                if(requiredCents < coinsDenominations[i]) {
                    //sum = sum +coinsDenominations[i-1];
                    if(denominations.containsKey(coinsDenominations[i-1])) {
                        int c = denominations.get(coinsDenominations[i-1]);
                        denominations.put(coinsDenominations[i-1], c+1);
                    } else {
                        denominations.put(coinsDenominations[i-1], 1);
                    }
                    requiredCents = requiredCents - coinsDenominations[i-1];
                    break;
                }
            }
        }
        return denominations;
    }

    public static void main(String[] args) {
        System.out.println(giveCoins(199));
    }

}

答案 21 :(得分:0)

一方面,这已得到回答。另一方面,大多数答案需要多行代码。这个Python答案不需要很多代码行,只需要很多思路^ _ ^:

div_round_up = lambda a, b: a // b if a % b == 0 else a // b + 1

def optimum_change(*coins):
    wallet = [0 for i in range(0, len(coins) - 1)]
    for j in range(0, len(wallet)):
        target = coins[j + 1] - 1 
        target -= sum(wallet[i] * coins[i] for i in range(0, j))
        wallet[j] = max(0, div_round_up(target, coins[j]))
    return wallet

optimum_change(1, 5, 10, 25, 100)
#  [4, 1, 2, 3]

这是一个非常简单的重新缩放算法,可能会破坏我尚未考虑的输入,但我认为它应该是健壮的。它基本上说,“为钱包添加新的硬币类型,查看下一个硬币类型N,然后添加制作target = N - 1所需的新硬币数量。”它计算出你至少需要ceil((target - wallet_value)/coin_value)这样做,并且不会检查这是否也会使每个数字都在中间。请注意,语法通过附加最终数字“100”来编码“从0到99美分”,因为这会产生适当的最终target

它不检查的原因是,“如果可以,它会自动进行检查。”更直接地说,一旦你为一分钱(值1)执行此步骤,算法可以将镍(值5)“分解”到任何子区间0 - 4.一旦你做了镍,算法现在可以“破坏” “一角钱(价值10)。等等。

当然,它不需要那些特定的输入;你也可以使用奇怪的货币:

>>> optimum_change(1, 4, 7, 8, 100)
[3, 1, 0, 12]

注意它是如何自动忽略7硬币的,因为它知道它已经可以通过它的变化“打破”8。

答案 22 :(得分:0)

这是我的解决方案,再次使用Python并使用动态编程。首先,我为1..99范围内的每个金额生成所需的最小硬币序列,并从该结果中找出每个面额所需的最大硬币数量:

def min_any_change():
    V, C = [1, 5, 10, 25], 99
    mxP, mxN, mxD, mxQ = 0, 0, 0, 0
    solution = min_change_table(V, C)
    for i in xrange(1, C+1):
        cP, cN, cD, cQ = 0, 0, 0, 0
        while i:
            coin = V[solution[i]]
            if coin == 1:
                cP += 1
            elif coin == 5:
                cN += 1
            elif coin == 10:
                cD += 1
            else:
                cQ += 1
            i -= coin
        if cP > mxP:
            mxP = cP
        if cN > mxN:
            mxN = cN
        if cD > mxD:
            mxD = cD
        if cQ > mxQ:
            mxQ = cQ
    return {'pennies':mxP, 'nickels':mxN, 'dimes':mxD, 'quarters':mxQ}

def min_change_table(V, C):
    m, n, minIdx = C+1, len(V), 0
    table, solution = [0] * m, [0] * m
    for i in xrange(1, m):
        minNum = float('inf')
        for j in xrange(n):
            if V[j] <= i and 1 + table[i - V[j]] < minNum:
                minNum = 1 + table[i - V[j]]
                minIdx = j
        table[i] = minNum
        solution[i] = minIdx
    return solution

执行min_any_change()会产生我们正在寻找的答案:{'pennies': 4, 'nickels': 1, 'dimes': 2, 'quarters': 3}。作为测试,我们可以尝试移除任何面额的硬币并检查是否仍然可以对1..99范围内的任何金额进行更改:

from itertools import combinations

def test(lst):
    sums = all_sums(lst)
    return all(i in sums for i in xrange(1, 100))

def all_sums(lst):
    combs = []
    for i in xrange(len(lst)+1):
        combs += combinations(lst, i)
    return set(sum(s) for s in combs)

如果我们测试上面获得的结果,我们得到True

test([1, 1, 1, 1, 5, 10, 10, 25, 25, 25])

但如果我们删除一枚硬币,无论面额是多少,我们都会获得False

test([1, 1, 1, 5, 10, 10, 25, 25, 25])

答案 23 :(得分:0)

我为DP编写类似问题的这个算法,可能有帮助

public class MinimumCoinProblem {

    private static void calculateMinumCoins(int[] array_Coins, int sum) {

        int[] array_best = new int[sum];

        for (int i = 0; i < sum; i++) {
            for (int j = 0; j < array_Coins.length; j++) {
                    if (array_Coins[j] <= i  && (array_best[i] == 0 || (array_best[i - array_Coins[j]] + 1) <= array_best[i])) {
                        array_best[i] = array_best[i - array_Coins[j]] + 1;
                    }
            }
        }
        System.err.println("The Value is" + array_best[14]);

    }


    public static void main(String[] args) {
        int[] sequence1 = {11, 9,1, 3, 5,2 ,20};
        int sum = 30;
        calculateMinumCoins(sequence1, sum);
    }

}

答案 24 :(得分:0)

这是Python中的一个简单版本。

#!/usr/bin/env python

required = []
coins = [25, 10, 5, 1]

t = []
for i in range(1, 100):
    while sum(t) != i:
        for c in coins:
            if sum(t) + c <= i:
                t.append(c)
                break
    for c in coins:
        while t.count(c) > required.count(c):
            required.append(c)
    del t[:]

print required

运行时,会将以下内容输出到标准输出。

[1, 1, 1, 1, 5, 10, 10, 25, 25, 25]

代码非常明显(感谢Python!),但基本上算法是添加最大的可用硬币,不会让你超过你当前拍摄的总数到你的临时硬币列表中(t在这种情况下)。一旦找到特定总数的最有效的硬币组,请确保所需列表中的每个硬币至少有那么多。这样做每1到99美分,你就完成了。

答案 25 :(得分:0)

vb版

Public Class Form1

    Private Sub Button1_Click(ByVal sender As System.Object, _
                              ByVal e As System.EventArgs) Handles Button1.Click
        For saleAMT As Decimal = 0.01D To 0.99D Step 0.01D
            Dim foo As New CashDrawer(0, 0, 0)
            Dim chg As List(Of Money) = foo.MakeChange(saleAMT, 1D)
            Dim t As Decimal = 1 - saleAMT
            Debug.WriteLine(t.ToString("C2"))
            For Each c As Money In chg
                Debug.WriteLine(String.Format("{0} of {1}", c.Count.ToString("N0"), c.moneyValue.ToString("C2")))
            Next
        Next
    End Sub

    Class CashDrawer

        Private _drawer As List(Of Money)

        Public Sub New(Optional ByVal QTYtwoD As Integer = -1, _
                       Optional ByVal QTYoneD As Integer = -1, _
                       Optional ByVal QTYfifty As Integer = -1, _
                       Optional ByVal QTYquarters As Integer = -1, _
                       Optional ByVal QTYdimes As Integer = -1, _
                       Optional ByVal QTYnickels As Integer = -1, _
                       Optional ByVal QTYpennies As Integer = -1)
            _drawer = New List(Of Money)
            _drawer.Add(New Money(2D, QTYtwoD))
            _drawer.Add(New Money(1D, QTYoneD))
            _drawer.Add(New Money(0.5D, QTYfifty))
            _drawer.Add(New Money(0.25D, QTYquarters))
            _drawer.Add(New Money(0.1D, QTYdimes))
            _drawer.Add(New Money(0.05D, QTYnickels))
            _drawer.Add(New Money(0.01D, QTYpennies))
        End Sub

        Public Function MakeChange(ByVal SaleAmt As Decimal, _
                                   ByVal amountTendered As Decimal) As List(Of Money)
            Dim change As Decimal = amountTendered - SaleAmt
            Dim rv As New List(Of Money)
            For Each c As Money In Me._drawer
                change -= (c.NumberOf(change) * c.moneyValue)
                If c.Count > 0 Then
                    rv.Add(c)
                End If
            Next
            If change <> 0D Then Throw New ArithmeticException
            Return rv
        End Function
    End Class

    Class Money
        '-1 equals unlimited qty
        Private _qty As Decimal 'quantity in drawer
        Private _value As Decimal 'value money
        Private _count As Decimal = 0D

        Public Sub New(ByVal theValue As Decimal, _
                       ByVal theQTY As Decimal)
            Me._value = theValue
            Me._qty = theQTY
        End Sub

        ReadOnly Property moneyValue As Decimal
            Get
                Return Me._value
            End Get
        End Property

        Public Function NumberOf(ByVal theAmount As Decimal) As Decimal
            If (Me._qty > 0 OrElse Me._qty = -1) AndAlso Me._value <= theAmount Then
                Dim ct As Decimal = Math.Floor(theAmount / Me._value)
                If Me._qty <> -1D Then 'qty?
                    'limited qty
                    If ct > Me._qty Then 'enough 
                        'no
                        Me._count = Me._qty
                        Me._qty = 0D
                    Else
                        'yes
                        Me._count = ct
                        Me._qty -= ct
                    End If
                Else
                    'unlimited qty
                    Me._count = ct
                End If
            End If
            Return Me._count
        End Function

        ReadOnly Property Count As Decimal
            Get
                Return Me._count
            End Get
        End Property
    End Class
End Class

答案 26 :(得分:0)

一般情况下,如果你有你的硬币COIN []和你的“更改范围”1..MAX,以下应该找到最大硬币数。

Initialise array CHANGEVAL[MAX] to -1

For each element coin in COIN:
  set CHANGEVAL[coin] to 1
Until there are no more -1 in CHANGEVAL:
  For each index I over CHANGEVAL:
    if CHANGEVAL[I] != -1:
      let coincount = CHANGEVAL[I]
      For each element coin in COIN:
        let sum = coin + I
        if (COINS[sum]=-1) OR ((coincount+1)<COINS[sum]):
          COINS[sum]=coincount+1

我不知道是否必须检查内部条件中的硬币最小性。我认为最小的硬币添加链最终会是正确的,但比抱歉更安全。

答案 27 :(得分:-1)

import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Scanner;

public class LeastNumofCoins 
{


    public int getNumofCoins(int amount)
        {
            int denominations[]={50,25,10,5,2,1};
            int numOfCoins=0;
            int index=0;
            while(amount>0)
            {
                int coin=denominations[index];
                 if(coin==amount)
                 {
                     numOfCoins++;
                     break;
                 }
                if(coin<=amount)
                    {
                        amount=amount-coin;
                        numOfCoins++;
                    }
                    else
                    {
                        index++;
                    }

            }
            return numOfCoins;
    }
    public static void main(String[] args) throws IOException 
    {

          Scanner scanner= new Scanner(new InputStreamReader(System.in));
          System.out.println("Enter the Amount:");
          int amoount=scanner.nextInt();
          System.out.println("Number of minimum coins required to make "+ amoount +" is "+new LeastNumofCoins().getNumofCoins(amoount));
          scanner.close();
    }
}