给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。
示例 1:
输入: coins = [1, 2, 5], amount = 11
输出: 3
解释: 11 = 5 + 5 + 1
示例 2:
输入: coins = [2], amount = 3
输出: -1
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/coin-change
解题思路:
这是一个动态规划类的算法题。
动态规划的解题思路:
一、确定状态:
1、状态在动态规划中的作用属于定海神针。
2、解动态规划的时候需要开一个数组。例如数组f[i]或者f[i][j]代表什么。
3、确定状态需要的两个意识: --最后一步,–子问题。
对于本题例如amount为27,coins[2,5,7]。
虽然我们不知道最优策略什么,但是最优策略肯定是K枚硬币a1,a2,…ak加起来等于27。所以一定有最后一枚硬币ak,所以除掉这枚硬币ak,剩下ak-1枚硬币相加等于27-ak。因为是最优策略,所以拼出27-ak的硬币数也是最少否则就不是最优策略。所以子问题就是:最少用多少枚硬币拼出27-ak。原问题是:最少用多少枚硬币拼出27。(我们将问题一样规模变小的称为子问题)我们设状态f(x)=最少用多少枚硬币拼出X。
最后一枚硬币可能是2,5,7中的任意一个。若最后一枚硬币是2,则f[x]=f(27-2)+1;若最后一枚硬币是5,则f[x]=f(27-5)+1;若最后一枚硬币是7,则f[x]=f(27-7)+1。
二、转移方程:
所以最后转移方程为:f[x]=Math.min{f(27-2)+1,f(27-5)+1,f(27-7)+1}。
三、初始条件和边界情况:
如果f(27-2),f(27-5),f(27-7)小于0怎么办?我们定义为正无穷。初始条件f[0]=0;
四、计算顺序:
对于此题我们是从小到大顺序,我们先计算f[0],f[1]…f[27]
代码:
class Solution {
public int coinChange(int[] coins, int amount) {
int[] f = new int[amount+1];
int n = coins.length;
f[0] = 0;
int i,j;
for(i=1;i<=amount;i++){
f[i] = Integer.MAX_VALUE;
for(j=0;j<n;j++){
if(i>=coins[j] && f[i - coins[j]] !=Integer.MAX_VALUE){
f[i] = Math.min(f[i-coins[j]]+1,f[i]);
}
}
}
if(f[amount] == Integer.MAX_VALUE){
f[amount]=-1;
}
return f[amount];
}
}
解析:首先开一个数组用来存放不同的钱数从1-amount所需要的硬币数。接着用n来存放硬币面值的数组长度。然后进行初始化零元钱需要零枚硬币。接着在for循环中实现转移方程,首先将所需要的硬币数赋值为无穷大,注意需要比较价价格是大于所给的硬币面值和所需的硬币数是否是正无穷。*