最低数量的硬币需要更改

时间:2018-05-26 09:10:57

标签: java algorithm dynamic-programming

我正在尝试打印最小数量的硬币进行更改,如果不可能打印-1

在这个代码变量int [] c(coins array)中有面额,我可以用它来得出总和。

int total总计我需要使用硬币(无限供应)

    public static int mincoinDP(int[] c, int total) {
        int[][] a = new int[c.length + 1][total + 1];

        for (int i = 0; i <= c.length; i++) {
            a[i][0] = 0;
        }
        for (int j = 1; j <= total; j++) {
            a[0][j] = Integer.MAX_VALUE - total;
        }

        for (int i = 1; i <= c.length; i++) {
            for (int j = 1; j <= total; j++) {
                if (c[i - 1] > j) {
                    a[i][j] = Integer.MAX_VALUE - total;
                } else {
                    a[i][j] = Math.min(a[i - 1][j], 1 + a[i][j - c[i - 1]]);
                }
            }
        }

        return a[c.length][total];
    }

对于Sum:4759和Array:{31 90 8 36}正确的输出是:59 我的输出是:60

代码有什么问题?

以下是我的递归解决方案,尝试在DP解决方案中应用相同的逻辑。这里的逻辑似乎也有些错误。对于相同的输入,它打印-2147483595

    public static void main(String[] args) {
        int[] array = new int[] {31, 90, 8, 36};
        System.out.println(mincoin(array, 4759, 0));
    }

    public static int mincoin(int[] c, int total, int i) {

        if (total == 0) return 0;
        if (i >= c.length) return Integer.MAX_VALUE;


        int x = Integer.MAX_VALUE, y = Integer.MAX_VALUE;

        if (total - c[i] >= 0) {
            x = 1 + mincoin(c, total - c[i], i);
        }
        y = mincoin(c, total, i + 1);

        return Math.min(x, y);
    }

编辑:代码中的问题是:

  1. DP版本:if(c [i -1]&gt; j),是解决方案不是的情况 可能选择这个硬币:在这里我们应该接受解决方案 这枚硬币是[i-1] [j]
  2. 递归版:if(i&gt; = c.length),     当我们在这个位置没有任何硬币时,这是终止条件,     这里我们应该返回无穷大(Integer.MAX_VALUE)和     避免整数溢出返回Integer.MAX_VALUE - total。
  3. 虽然我不喜欢这个版本的无限,但除此之外没有看到任何好的方法。

2 个答案:

答案 0 :(得分:1)

看起来您正在使用动态编程,a[i][j]旨在表示总和为j的最小硬币数(使用前i个面额)。但我认为你的复发关系是关闭的。他们应该是:

a[0][j] = 0 if j==0, otherwise infinity

a[i][j] = a[i-1][j] if c[i-1] > j
a[i][j] = min(a[i-1][j], 1 + a[i][j-c[i-1]]) if c[i-1] <= j

主要错误是代码中的if c[i-1] > j个案。您将值设置为无穷大(或无穷大的变体),但您应该只复制上一行中的最小硬币数,因为您可以使用较少数量的硬币构建总数。

顺便说一句,有一种更简洁的方式来编写这段代码。在伪代码中:

a = new int[total+1]
for int j = 1 to total+1 {
    a[j] = infinity
}
for int coin in coins {
    for j = coin to total+1 {
        a[j] = min(a[j], a[j-coin]+1)
    }
}

它基本上是相同的算法,但它使用较小的一维数组,它就地修改。

答案 1 :(得分:0)

以防万一有人在寻找解决方案

public int coinChange(int[] coins, int amount) {
    int dp[][] = new int[coins.length+1][amount+1];
    Arrays.sort(coins);
    
    // First column of every row
    for (int i = 0; i < coins.length; ++i) {
        dp[i][0] = 0;
    }

    /*
       Setting this so that this is default max value. We always
       want our dp[i][j] better than this
    */
    for (int j = 0; j <= amount; ++j) {
        dp[0][j] = amount+1;
    }
    
    for (int i = 1; i <= coins.length; ++i) {
        for (int j = 1; j <= amount; ++j) {
            if (coins[i-1] > j) {
               dp[i][j] = dp[i-1][j];   // Take the already best value in above row
            } else {
               dp[i][j] = Math.min(dp[i-1][j], 1 + dp[i][j-coins[i-1]]); // Take the best of above row and using current coin
            }
        }
    }
    if (dp[coins.length][amount] > amount) { // it means we cannot find any coin
        return -1;
    } else {
        return dp[coins.length][amount];
    }
}