Dynamic Programming学习笔记 (12) - 零钱兑换一 (力扣 #322)

126 阅读1分钟

零钱兑换一是个相对简单的DP问题,其题面为

给定一个整数数组 coins ,表示N种不同面额的硬币;以及一个整数 amount ,表示总金额。 计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回 -1 。

实例:

输入:coins = {1, 2, 5}, amount = 11
输出:3 
解释:11 = 5 + 5 + 1

解题思路在于首先定义一个F(k)函数,k是[1,amount]之间的整数,该函数返回的是金额为k时所需最少的硬币数量,对于给定的N种硬币,我们可以看出

F(k)
 = amount + 1, k < 0
 = 0,  k = 0
 = min of (1 + F(k - coin[0]), 1 + F(k - coin[1]) ... 1 + F(k - coin[N - 1]))
 

F(k)的边界情况为当k < 0时,返回amount + 1,因为没有任何组合可以凑成一个负数的金额,使用amount + 1以代表这种不可能的情况,

根据以上的表达式,我们可以使用一个一维数组作为DP存储,并依据k的数值从小到大依次计算DP数组种的各个元素,最后DP[amount]中的数据就是给定问题的答案。

Java代码如下

class Solution {
    public int coinChange(int[] coins, int amount) {
        if (amount == 0) {
            return 0;
        }

        int N = coins.length;

        int[] dp = new int[amount + 1];

        for (int k = 1; k<= amount; k ++) {
            int min = amount + 1;
            for (int j = 0; j < N; j ++) {
                if (k >= coins[j]) {
                    int n = 1 + dp[k - coins[j]];
                    min = Math.min(min, n);
                }
            }
            dp[k] = min;
        }

        if (dp[amount] > amount) {
            return -1;
        } else {
            return dp[amount];
        }
    }
}