我试图用递归的方法解决硬币兑换问题。问题是这样的:
你会得到不同面额的硬币和总金额。编写一个函数来计算组成该数量的组合数。
您将获得一个数量和一组硬币。
这是我到目前为止所拥有的:
private static int[] coins = {1,2,5};
public static void main(String[] args) {
System.out.println(count(13));
}
public static int count(int n)
{
// If n is 0 then there is 1 solution
if (n == 0)
return 1;
// If n is less than 0 then no solution exists
if (n < 0)
return 0;
return count(n - coins[0]) + count(n - coins[1]) + count(n - coins[2]);
}
当我这样做的时候,我没有得到任何接近正确的组合。我认为问题是回报,但我不明白为什么。在这里,我把硬币从数量中减去,每次都加在一起。当它得到0时,它返回1。
根据您的算法,penny-then-nickel被视为与nickel-then-penny不同的溶液。你应该执行特定的命令。(这在数学上称为排列和组合之间的差异。)
我会考虑添加一个硬币面值列表作为递归函数的第二个参数。然后,在每个步骤(除了一个终端步骤),你会考虑两种可能性:
(a)考虑添加另一枚硬币的可能性,但只有列表前面的面额中的一个。
B)考虑递归调用的可能性,其中您正在截断列表中的第一个元素。
这个问题的解决方案已经发布了,所以我假设你问的是如何思考它,而不是答案本身。
试试这个:
设V为目标值。
让C[i]成为第i个硬币的价值。
递归解决方案是指做出一个选择,减少问题的规模,然后在较小的问题上递归地使用相同的解决方案。
当问题很小,不需要重复就可以轻松解决时,我们只返回该解决方案。这就是“基本情况”
这里的选择是使用特定数量的硬币N[i]的价值C[i]。
对于N[i]的所有可能的值,我们需要这样做,即。N[i]=0,1,2,...地板(V/C[i])。整数层(V/C[i])是可能产生正确变化的第i个硬币的最大数量。
一旦我们决定了使用多少i'th硬币,我们就不应该改变这个决定。(这就是您的解决方案出错的地方。)实现这一点的最简单方法是利用货币数组html" target="_blank">索引的隐含顺序。对于目标值的剩余部分:V-N[i]*coins[i],我们递归地找到使用硬币i 1和更大的硬币进行更改的方法的数量。
(另一种设计是将硬币保留在一个集合中,并通过在重复出现之前从集合中移除硬币[i]来进行选择。但让我们继续使用索引,因为生成的代码更简单。)
为了产生结果,我们只需将所有递归确定的计数相加。
基于这种想法,我们可以为递归方法选择一个签名:
/**
* Return the number of ways to make change for the given value
* using coins i >= iMin.
*/
int count(int value, int iMin);
是时候考虑一下基本情况了。“成功”是指值
完全为零时:我们可以通过完全不做任何事情的方式以完全1的方式进行更改!当值
不为零,并且我们没有硬币值可供尝试时,就会出现“失败”。这正是iMin
达到coins
数组长度的时候。
让我们把这种想法转化为代码:
int count(int value, int iMin) {
if (value == 0) return 1; // Success base case.
if (iMin >= coins.length) return 0; // Failure base case.
result = 0;
for (int ni = 0; ni <= value / coins[iMin]; ++ni)
result += count(value - ni * coins[iMin], iMin + 1);
return result;
}
要开始递归,只需使用目标值和0的iMin:
int result = count(target, 0);
请注意,虽然此解决方案是正确的,但效率不高。让我们改天再讨论吧。
首先,你应该替换:
return count(n - coins[0]) + count(n - coins[1]) + count(n - coins[2]);
用循环:
int nCoins = 0;
for(int coin=0; coin<coins.length; coin++)
{
nCoins += count(n-coins[coin]);
}
return nCoins;
这样做的问题是,它会生成所有的硬币排列(=634)。要获得每个硬币的独特组合,您需要确保在当前硬币上开始每个级别的递归。为此,您需要在count方法中添加一个参数,以指示硬币数组中开始的位置。
public static int count(int n, int startCoin)
你的循环就变成了
int nCoins = 0;
for(int coin=startCoin; coin<coins.length; coin++)
{
nCoins += count(n-coins[coin], coin);
}
return nCoins;
这给出了正确的答案(14)。
我已经编写了一个代码,用来计算使用递归从1到100之间的任何值可以得到的更改可能性的数量。我不确定项目中的2个方法做了什么(代码中的粗体部分),所以有人能给我解释一下吗?我对Java还很陌生。 我包含了上下文的整个代码,但不确定是否有必要。
给定一个值N,如果我们想改变为N美分,并且我们有无限量的S={S1,S2,...,Sm}值的硬币,我们有多少种方法可以改变?硬币的顺序并不重要。不过还有一个额外的限制:你只能用正好是K的硬币换零钱。 例如,对于N=4,k=2和S={1,2,3},有两个解:{2,2},{1,3}。所以输出应该是2。 解决方案: 以上是递归解决方案。但是,我需要有关动态规划解决方案的帮助: 让表示与元素和硬币的总和。
我有一个低效的递归硬币变化函数,它计算出给定数量的硬币组合数量。如果可能的话,我想把它转换成一个更有效的迭代函数。 一个问题是,我正在使用回溯来尝试一个叫做面额的数组中的不同硬币。我也在使用记忆法,但当数量很大时,它不会加快速度。 这是我的密码: 有什么想法可以做到这一点吗?我知道有解决硬币更换问题的DP解决方案,但我的解决方案并不容易。我可以有半个便士。 *更新:我将函数改为迭代函数,并将其放大
我试图用递归来解决硬币兑换问题,遇到了下面的代码。 问题:给定一些面额的无限硬币,计算它们形成给定数量的方式。 输入: 代码: 我理解代码本身,也理解基本情况,但是我不理解它是如何封装递归/解决方案的。 例如,如果我正在求解,我可以说,因此我可以清楚地“看到”递归。在换硬币的例子中,我无法推断出类似的关系。有人能帮我吗?
我有一个关于如何将“递归”转换为“尾部递归”的问题。 这不是家庭作业,只是在我试图润色算法书籍中的递归定理时出现的一个问题。 我熟悉使用递归的两个典型示例(阶乘和斐波那契序列),也知道如何以递归方式和尾部递归方式实现它们。 我的代码如下(我使用Perl只是为了使其简单,但可以轻松地转换为C/Java/C)。 运行代码时,输出如下: 递归函数在返回之前使用不同的参数调用自己两次。我尝试了几种方法将其
我想知道是否有一些通用方法可以用foo(…)转换“正常”递归foo(…) 作为尾部递归的最后一个调用。 例如(scala): 函数语言将递归函数转换为等价尾部调用的一般解决方案: 一种简单的方法是将非尾部递归函数包装在蹦床单子中。 所以pascal函数不再是递归函数。然而,蹦床单子是需要完成的计算的嵌套结构。最后,是一个尾递归函数,它遍历树状结构,解释它,最后在基本情况下返回值。 Rúnar Bj