LeetCode 322
问题描述
给定不同面额的硬币 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
解题思路
这道题,可以采用多种方式来解决。这里使用动态规划来解题。首先,找出状态转移方程。
- 已知硬币面值coins[],用这些硬币凑成指定的金额amount。要求硬币个数最少。
- 设金额amount对应的最少硬币个数为:f(amount)
- 自上而下推,我们可以这样想,金额amount对应的最少硬币数f(amount),肯定是由另一个金额加上一个已有的硬币面值来的。
可以得出:
f(amount) = min(f(amount-coins[0]),f(amount-coins[1])…)+1
代码
- 解题思路是从上向下,但是按照这个思路写代码时,会比较麻烦。可以考虑自下而上的方式。
- 初始化数组dp[amount+1],下标表示金额,值为最少硬币数。
dp[coins[0]]=dp[coins[i]]=…=1 - 由初始化后的数组,可推出之后所有的金额的最少硬币数。
dp[i+coins[n]] = dp[i+coins[n]]>dp[i]+1?dp[i]+1:dp[i+coins[n]];
public static int solution(int[] coins,int amount){
int flag[] = new int[amount+1];
if (amount == 0)
return 0;
for (int j = 0;j<=amount;j++){
for (int i = 0;i<coins.length;i++){
if (coins[i]>amount)
continue;
if (j+coins[i] <= amount)
if ((flag[j]!=0||j == 0)&&(flag[j+coins[i]]>flag[j]+1||flag[j+coins[i]]==0))
flag[j+coins[i]] = flag[j]+1;
}
}
return flag[amount]==0?-1:flag[amount];
}