【问题标题】:Understanding coin change recursion了解硬币找零递归
【发布时间】:2021-02-15 21:05:49
【问题描述】:

我试图专门使用 recursion 解决硬币找零问题,结果遇到了以下代码。

问题:给定一些面额的无限硬币,计算数量。给定数量可以由它们形成的方式。

输入:

int[] coins = {1, 2}; 
int amount = 5;
int ways = change(amount, coins, coins.length - 1);
// expected ways = 3 --> 11111, 1112, 122

代码:

int change(int amount, int[] coins, int index) {
    if (amount < 0) return 0;
    if (amount == 0) return 1;
    
    int ways = 0;
    while (amount > 0 && index >= 0) {
        ways += change(amount - coins[index], coins, index);
        index = index - 1;
    }
    return ways;
}

我了解代码本身,也了解基本情况,但我无法了解它如何封装递归/解决方案。

例如。如果我正在解决factorial(n),我可以说factorial(n) = n * factorial(n-1),所以我可以清楚地“看到”递归。我无法在硬币变化示例中推断出类似的关系。谁能帮我解决这个问题?

【问题讨论】:

  • 计算制造 50 个货币单位的方法数量的一部分是说“如果我使用 10 个单位的硬币,那么我就必须补足剩下的 40 个单位:有多少种方法是那?”。这就是递归关系。
  • 这就是我想要达到的目标!你能详细说明一下吗?因此,如果我想从{2, 1} 获取5,我需要在从{2, 1} 获取3 的解决方案中添加什么?基本上在阶乘递归中,我必须将 n 乘以先前的解决方案。这里对应的概念是什么?
  • 从2和1做成5,可以从2开始,那么剩下的3有很多方法;或者你可以从 1 开始,那么剩下的 4 有很多种方法。这两个选项结合起来给出了 5 的方法数。
  • 谢谢!仍然不是 100% 清楚,但我会花一些时间在上面。

标签: java recursion coin-change


【解决方案1】:

递归行在这里:ways += change(amount - coins[index], coins, index);

我已经注释了代码来解释一下。

//amount is the total value we want all our coins to add up to
//coins carries the values we can add up to get the amount
//index is the coin we're "on" right now - we'll explain this more in a bit
int change(int amount, int[] coins, int index) {

    //we went too low: out last coin was too large and pushed us into negatives
    if (amount < 0) return 0;
    //exact change! we found a new way to make change with these coins
    if (amount == 0) return 1;
    
    //count the number of ways we can make the change
    int ways = 0;

    //here's where the recursion starts: we start at index, which is the number of
    //coins available to us. in this case, we're going right to the end of the
    //array to the "2" coin. we'll repeatedly subtract "2" from the amount until
    //we hit 0, meaning we were able to meet the amount using only "2" coins, or
    //we're unable to go any further.
    //if we're unable to go further, we return one level up from the recursion,
    //and decrease index by 1: this means we're now trying the "1" coin. 
    //this process repeats, making as much change with the "2" coin as we can and
    //falling back to the "1" coin when we get stuck or reach the bottom of the
    //recursion.
    while (amount > 0 && index >= 0) {
        //try to use this same coin over and over, and when the function returns,
        //whether through success or failure...
        ways += change(amount - coins[index], coins, index);
        //...move onto the next coin and repeat the process.
        index = index - 1;
    }
 
    //the total number of times we were able to make exact change with these coins
    return ways;
}

通俗地说:

desired value: 5    available coins: 1, 2
value = 5
coin = 2
5 - 2 = 3

. value = 3
. coin = 2
. 3 - 2 = 1

. . value = 1
. . coin = 2
. . 1 - 2 = -1 | fail
. . coin = 1
. . 1 - 1 = 0 | success
. . no more coins to try

. value = 3
. coin = 1
. 3 - 1 = 2

. . value = 2
. . coin = 1
. . 2 - 1 = 1

. . . value = 1
. . . coin = 1
. . . 1 - 1 = 0 | success
. . . no more coins to try

. . no more coins to try

. no more coins to try

value = 5
coin = 1
5 - 1 = 4

. value = 4
[...and so on]

【讨论】:

  • 感谢您抽出宝贵时间回答和编写 cmets,我完全理解代码,但试图理解递归,即如何从以前的解决方案中获得当前解决方案。
  • @Ufder 最简单的方法:拿一张纸和一支笔,画出代码的路径:每次返回时向前和向后。当你回到起点时,这将是有意义的
  • @Ufder 我添加了视觉解释。
  • @Ufder "选择最大的硬币,并从总金额中尽可能多地减去它。如果你击中负数,撤消最后的减法,选择下一个最小的硬币,然后继续尝试。如果你击中 0,则视为成功 - 记录它,然后撤消减法,直到你得到你正在使用的前一个硬币。将其更改为当前硬币,然后重复。这样做直到你测试了每一个硬币。 (请注意,为了便于说明,本例中的硬币按大小排序,但您不需要对它们进行排序以使算法正常工作。)
  • @NickReed Dude,所有那些他们说Pick a coin vs Discard a coin 的 youtube 视频,我无法理解,但是一旦我看到你的评论,我马上就明白了。谢谢!!
猜你喜欢
  • 1970-01-01
  • 2020-04-11
  • 2023-03-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-11-19
  • 2015-07-04
相关资源
最近更新 更多