给你一个整数数组 coins ,表示不同面额的硬币;以及一个整数 amount ,表示总金额。
计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回 -1 。
你可以认为每种硬币的数量是无限的。
思路:
这类涉及状态转移的题目,可以考虑动态规划。
具体做法:
- step 1:可以用dp[i]dp[i]dp[i]表示要凑出i元钱需要最小的货币数。
- step 2:一开始都设置为最大值aim+1aim+1aim+1,因此货币最小1元,即货币数不会超过aimaimaim.
- step 3:初始化dp[0]=0dp[0]=0dp[0]=0。
- step 4:后续遍历1元到aim元,枚举每种面值的货币都可能组成的情况,取每次的最小值即可,转移方程为dp[i]=min(dp[i],dp[i−arr[j]]+1) dp[i] = min(dp[i], dp[i - arr[j]] + 1)dp[i]=min(dp[i],dp[i−arr[j]]+1).
- step 5:最后比较dp[aim]dp[aim]dp[aim]的值是否超过aim,如果超过说明无解,否则返回即可。
Java实现代码:
import java.util.*;
public class Solution {
public int minMoney (int[] arr, int aim) {
//小于1的都返回0
if(aim < 1)
return 0;
int[] dp = new int[aim + 1];
//dp[i]表示凑齐i元最少需要多少货币数
Arrays.fill(dp, aim + 1);
dp[0] = 0;
//遍历1-aim元
for(int i = 1; i <= aim; i++){
//每种面值的货币都要枚举
for(int j = 0; j < arr.length; j++){
//如果面值不超过要凑的钱才能用
if(arr[j] <= i)
//维护最小值
dp[i] = Math.min(dp[i], dp[i - arr[j]] + 1);
}
}
//如果最终答案大于aim代表无解
return dp[aim] > aim ? -1 : dp[aim];
}