找到一个数字的最小数量的硬币

时间:2012-10-16 05:21:44

标签: java permutation

  

可能重复:
  Most optimal coin fit for a given sum of money

我正在接受一些练习面试的问题,这一直困扰着我。这是问题:

  

给定硬币1c,7c,13c和19c返回具有所需硬币数量最少的字符串>表示X的输入。

现在,我已经很容易地解决了这个问题,之后它就像1c,5c,10c和25c这样的简单面额。这只是一个简单的贪心算法。为此,我认为这将是某种排列问题,但我不知道如何获得最低限度。有任何想法吗?这是我的一些伪代码:

String coinDenominations(double amount, String coins)
{
    if(amount > .19) coinDenominations(amount - .19, coins + "19 ");
    if(amount > .13) coinDenominations(amount - .13, coins + "13 ");
    if(amount > .07) coinDenominations(amount - .07, coins + "7 ");
    if(amount > .01) coinDenominations(amount - .01, coins + "1 ");
    if(amount == 0) System.out.println(coins);
}

我的排列很生疏,但我认为这会输出可能的组合。我怎么能找到最小的金额呢?有没有更好的非递归方式呢?

3 个答案:

答案 0 :(得分:0)

我认为可以这样做。

金额是x。硬币是1c,7c,13c& 19C。

算法如下。

x = x * 100;

need_19 = x / 19;

y = x%19;

need_13 = y / 13;

y = y%13;

need_7 = y / 7;

y = y%7;

need_1 = y;

total_coins = need_19 + need_13 + need_7 + + need_1;

答案 1 :(得分:0)

我认为我们可以这样写:

String coinDenominations(double amount){
   int[] coinDenom = new int[] {19,13,7,1};
   int amountInCents = amount*100;
   String coinDenomString = "";
   for(int i=0; i< coinDenom.length; i++){
       coinDenomString = coinDenomString + ((int)(amountInCents/coinDenom[i])) 
                         + "of +"  coinDenom[i] + "coins";
       amountInCents = amountInCents % coinDenom[i];
   }
   return coinDenomString;
}

我相信,上面的也可以转换为递归。

答案 2 :(得分:0)

正如this answer中所提到的,某些硬币组合可能适用于贪婪的算法,但并不能保证贪婪会为所有硬币组合提供最佳组合。

Python中的一种详尽的递归解决方案(伪代码的理想语言)如下所示。

请注意,这会为您提供排列而不是组合,但是,如果您想过滤掉重复项(就组合而言),则在创建列表后进行排序和过滤会很简单。

另请注意,对于较大金额而言,这可能相当可怕。例如,虽然对于像27或75这样的输入值,它在一秒钟之内,但是在我感到无聊并取消之前,1024的输入至少需要几分钟。

import sys

oldcount = 99999999
lst = []

def recurse (str, amt, count):
    global oldcount
    global lst
    if amt < 0: return
    if count > oldcount: return
    if amt == 0:
        if count < oldcount:
            print "====="
            lst = []
            oldcount = count
        if count == oldcount:
            lst.append (str)
        return
    recurse ("%s 19" % str, amt - 19, count + 1)
    recurse ("%s 13" % str, amt - 13, count + 1)
    recurse ("%s  7" % str, amt -  7, count + 1)
    recurse ("%s  1" % str, amt -  1, count + 1)

recurse ("", int (sys.argv[1]), 0)
#for seq in lst: print seq
print "%d permutations" % len (lst)

注意,对于面额{1, 7, 13, 19}(这种特殊情况),贪婪算法 是最好的,其“证据”是(a)

对于任何值1到6,你使用那么多1个硬币,这就是贪婪算法给你的。

对于任何7到12的值,您可以使用那么多1个硬币,也可以使用7来减少7个1个硬币。贪婪算法为你提供了后一种情况,这是正确的,因为最好带走七个1硬币并添加一个7硬币 - 它会将硬币数量减少六个。

对于值13到18,您无法使用137,因为这将至少为20,因此您会遇到13/1混合或7/1混合(所有1硬币出于与上一段中相同的原因 - 为单个1硬币交换13 13个硬币是一个大幅减少)。显然,13值的最佳选择是单个13硬币,但可以使用7/713/1(两个硬币)实现14。然后,值15到18只添加了1个硬币。

同样,19值是单个硬币19,而20值可以由19/113/7表示。从21到37(在19/19值38之前)的值为19加上前三段中的最小混合。

因此,由于所选择的值(17不同,7/7 == 13/17/7/7 == 19/1/113/7 == 19/1等等,贪婪的算法运行得很好(我不相信那些值是随机选择的,这太方便了。)

最小硬币计数表如下:

Value  Count  Possibilities
    1      1  1
    2      2  1x2
    3      3  1x3
    4      4  1x4
    5      5  1x5
    6      6  1x6
    7      1  7
    8      2  7,1
    9      3  7,1x2
    :
   12      6  7,1x5
   13      1  13
   14      2  13,1 or 7x2
   15      2  13,1x2 or 7x2,1
    :
   18      6  13,1X5 or 7x2,1x4
   19      1  19
   20      2  19,1 or 13,7
   21      3  19,1x2 or 13,7,1 or 7x3
    :

等等。


(a)不是正式证明,但我确信我是对的,我会向第一个向我展示的人提出20个问题/答案一个反例(提供问题和答案当然不是完全垃圾 - 我必须认为它们是有用的,以免破坏投票过程。)