Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/337.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 换币递归法_Java_Recursion - Fatal编程技术网

Java 换币递归法

Java 换币递归法,java,recursion,Java,Recursion,我试图用递归的方法解决硬币兑换问题。问题是这样的: 你会得到不同面额的硬币和总金额。编写一个函数来计算组成该数量的组合数 您将获得一个数量和一组硬币 以下是我到目前为止的情况: 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

我试图用递归的方法解决硬币兑换问题。问题是这样的:

你会得到不同面额的硬币和总金额。编写一个函数来计算组成该数量的组合数

您将获得一个数量和一组硬币

以下是我到目前为止的情况:

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]);
}
private static int[]coins={1,2,5};
公共静态void main(字符串[]args){
系统输出打印项次(计数(13));
}
公共静态整数计数(整数n)
{
//如果n为0,则有1个解
如果(n==0)
返回1;
//如果n小于0,则不存在解决方案
if(n<0)
返回0;
返回计数(n-硬币[0])+计数(n-硬币[1])+计数(n-硬币[2]);
}

当我这样做的时候,我没有得到任何接近正确组合的东西。我认为问题在于退货,但我不明白原因。在这里,我从数量中减去硬币,然后每次将它们相加。当它得到0时,返回1。

根据您的算法,penny-then-nickel被视为与nickel-then-penny不同的溶液。你应该执行特定的命令。(这在数学上称为排列和组合之间的差异。)

我会考虑添加一个硬币面值表作为递归函数的第二个参数。然后,在每个步骤(除了一个终端步骤),你会考虑两种可能性:

(P> a)考虑添加另一枚硬币的可能性,但只有列表前面的面额之一


b)考虑递归调用的可能性,其中你正在截断列表中的第一个元素

,我还没有足够的评论来评论,我目前正在研究解决你的问题。我在您当前的代码中注意到一个缺陷:您正在跟踪“唯一排列”(我不知道正式的数学名称是什么),而不是“类似排列”,我相信您会这样做

例如,如果您想查找计数(5),您将获得以下九(9)种可能的排列/方式以获得5:

[2,2,1]、[2,1,2]、[1,2,2]、[5]、[2,1,1,1]、[1,2,1]、[1,1,1,2]、[1,1,1,2]和[1,1,1,1,1,1]

虽然我相信您只想返回四(4)个以下排列:

[1,1,1,1,1],[2,1,1],[2,2,1],[5]

以下是我认为可以进一步回答您问题的链接。请在以后提问之前搜索堆栈溢出


这个问题的解决方案已经发布,所以我假设你问的是如何思考它,而不是答案本身

试试这个:

设V为目标值

让C[i]成为第i个硬币的价值

递归解决方案是指做出一个选择,减少问题的规模,然后在较小的问题上递归地使用相同的解决方案

当问题很小,不需要重复就可以轻松解决时,我们只返回该解决方案。这就是“基本情况”

这里的选择是使用一个特定数量的N[i]值为C[i]的硬币

我们需要对N[i]的所有可能值进行分析,即N[i]=0,1,2,…楼层(V/C[i])。整数下限(V/C[i])只是可能产生正确变化的第i个硬币的最大数量

一旦我们决定了使用多少i'th硬币,我们就不应该改变这个决定。(这就是你的解决方案出错的地方。)实现这一点的最简单方法是利用硬币数组索引的隐含顺序。对于目标值的剩余部分: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;
}

请注意,虽然此解决方案是正确的,但效率不高。让我们把讨论留到另一天。

首先,您应该替换:

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;
然后,您的循环变为

int nCoins = 0;
for(int coin=startCoin; coin<coins.length; coin++)
{
    nCoins += count(n-coins[coin], coin);
}
return nCoins;
int nCoins=0;

对于(int coin=startCoin;coin除非你改变它,否则你会得到stackoverflow错误…查看调用尾部修剪,在这里你将方法的值存储在你计算的每个值上,所以当你再次调用它时,你只需查看数组而不是重新计算它。你能详细说明一下你的意思吗?@user081608我不明白e你对哪一部分感到困惑,但我已经用更多细节更新了我的答案。如何在此基础上添加备忘录?
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;