题意
给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。
你可以认为每种硬币的数量是无限的。
输入:coins =[1, 2, 5], amount =11
输出:3
解释:11 = 5 + 5 + 1
题目分析
1. 确定状态
最优策略一定是是K
枚硬币,
a
1
,
a
2
,
.
.
.
,
a
k
a_1,a_2,...,a_k
a1,a2,...,ak组成,并且
a
1
+
a
2
+
.
.
.
+
a
k
=
a
m
o
u
n
t
a_1+a_2+...+a_k=amount
a1+a2+...+ak=amount。
最后一步
最后一枚硬币 a k a_k ak也是 [ 1 , 2 , 5 ] [1,2,5] [1,2,5]中的一个,并且前边所有硬币的和是 a m o u n t − a k amount-a_k amount−ak。
子问题
原问题转化为,求凑成 a m o u n t − a k amount-a_k amount−ak最少的硬币个数。
状态
f
[
i
]
f[i]
f[i]表示凑成总金额i
所需的最少的硬币个数
2. 转移方程
f [ i ] = m i n j ∈ c o n i s f [ i − j ] + 1 f[i]=min_{j\in conis}{f[i-j]}+1 f[i]=minj∈conisf[i−j]+1
i f ( f [ i − j ] < 0 ) , f [ i − j ] = + ∞ if(f[i-j] < 0), f[i-j] = +\infty if(f[i−j]<0),f[i−j]=+∞
3. 初始条件和边界情况
f [ 0 ] = 0 f[0]=0 f[0]=0
4. 计算顺序
f [ 0 ] , f [ 1 ] , f [ 2 ] , f [ 3 ] , . . . f[0],f[1],f[2],f[3],... f[0],f[1],f[2],f[3],...
Code
class Solution {
public int coinChange(int[] coins, int amount) {
int[] dp = new int[amount+1];
Arrays.fill(dp, Integer.MAX_VALUE);
dp[0] = 0;
for(int i = 1; i <= amount; i++) {
for(int j = 0; j < coins.length; j++) {
if(i >= coins[j] && dp[i-coins[j]] != Integer.MAX_VALUE) {
dp[i] = Math.min(dp[i], dp[i-coins[j]] + 1);
}
}
}
return dp[amount] == Integer.MAX_VALUE ? -1 : dp[amount];
}
}