LeetCode刷题:322. Coin Change

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/seagal890/article/details/89076718

LeetCode刷题:322. Coin Change

原题链接:https://leetcode.com/problems/coin-change/

You are given coins of different denominations and a total amount of money amount. Write a function to compute the fewest number of coins that you need to make up that amount. If that amount of money cannot be made up by any combination of the coins, return -1.

Example 1:

Input: coins = [1, 2, 5], amount = 11
Output: 3 
Explanation: 11 = 5 + 5 + 1
Example 2:

Input: coins = [2], amount = 3
Output: -1
Note:
You may assume that you have an infinite number of each kind of coin.

题目大意:

你会得到不同面值的硬币和总金额。写一个函数来计算你所需要的最少的硬币数量面值之和满足总金额。

如果这些硬币的任何组合都不能满足这个总金额,则返回-1。

算法分析:

这个问题如果使用贪心算法(Greedy)解题的话,在一些情况下会得到错误的答案。

例如:coins的面值为[1,99,100],amount=396.

这时候,采用贪心算法会怎么选择呢?会选择面值100的3个;接下来呢?会选择96个1吗?显然不正确。

而 396 = 99*4. 这个是正确的解。

该问题可使用动态规划来解决。

构建一个数组dp[amount + 1]用于记录从0 ~ amount每个数用coins组合的最小次数(对于每个数,组合次数的上限不可能超过amount + 1,因此可将数组初始化为amount + 1,这样,对于某一下标i,只要出现合法的组合,就可以使用min函数覆盖掉amount + 1,若执行算法后该下标所对应的值仍为amount + 1,说明无法在coins中找出一个组合来表示i)

根据以上思路,可写出状态转移方程:

dp[x + coins] = min(dp[x] + 1, dp[x + coins])

其中dp[x]代表凑齐金额x所需的最少硬币数,coins表示可用的硬币面值,在coins数组中遍历。

注意在算法执行前,令dp[0] = 0。

算法设计:

public int coinChange(int[] coins, int amount) {
		
		if (coins == null || coins.length == 0 || amount == 0) 
			return 0;
		
        int max = amount + 1;   
        /*
         * 开辟一个dp数组,dp数组的长度为:amount+1
         * dp数组的含义:
         * dp[i]的含义是表示钱数是i时的最少硬币数。
         * */
        
        int[] dp = new int[amount + 1];  
        //初始化dp数组元素
        Arrays.fill(dp, max);  
        //dp[0]赋初值为0
        dp[0] = 0;   
        
        for (int i = 1; i <= amount; i++) {
            for (int j = 0; j < coins.length; j++) {
                if (coins[j] <= i) {
                    /*
                     * 我们维护一个动态一维数组,其中dp[i]表示钱数为i时的最小硬币的找零。
                     * 对于满足条件的每一个硬币,状态转移方程为:
                     * dp[i] = min(dp[i], dp[i - coins[j]] + 1)
                     * 从上面式子,可知,我们需要给dp[i]赋初值,这个初值赋值为可能的最大值。
                     * 也就是需要找零的面额amount+1的值。
                     * 如果存在能够进行找零的情况,那么最终的dp[i]的值一定是比amount+1少的。
                     * 
                     * 那么如果不存在能够找零的情况呢?
                     * 比如对于coins = [2],amount = 9的情况。是一定不存在找零情况的。
                     * 那么进行动态规划的时候,自底向上,遇到1,3,5,7的情况会怎么样呢?
                     * 还是按照上面的式子,我们会发现,遇到9的时候,会减2,到7中找结果。
                     * 而7的结果从5,3,1得来,结果是amount+1+1=amount+2。
                     * 这样进行比较得到的最小值,就还是amount+1。
                     * 一维数组中,如果值是amount+1,就说明这个面额是不存在找零情况的。
                     * 因此,对于amount不能找零,只需要在最后判断一下是不是等于amount+1即可,如果等于就返回-1。
                     * */
                	dp[i] = Math.min(dp[i], dp[i - coins[j]] + 1);
                }
            }
        }
        //
        return dp[amount] > amount ? -1 : dp[amount];
    }
	

猜你喜欢

转载自blog.csdn.net/seagal890/article/details/89076718
今日推荐