题解 | #兑换零钱(一)#
兑换零钱(一)
https://www.nowcoder.com/practice/3911a20b3f8743058214ceaa099eeb45
import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
* 最少货币数
* @param arr int整型一维数组 the array
* @param aim int整型 the target
* @return int整型
*/
public int minMoney (int[] arr, int aim) {
// write code here
// 算法核心:动态规划(由于状态转移是基于for循环的,因此记忆化搜索不能够与动态规划相媲美了)
// 先处理特殊值
if (aim == 0) {
return 0;
}
if (arr.length == 0) {
return -1;
}
// dp[i][j] - 考虑第i个及以后的币种,目标是凑齐j,所需要的最少货币数
// 先统一初始化成Integer.MAX_VALUE
int[][] dp = new int[arr.length + 1][aim + 1];
for (int i = 0; i < dp.length; i++) {
for (int j = 0; j < dp[0].length; j++) {
dp[i][j] = Integer.MAX_VALUE;
}
}
// 初始化:对于[arr.length][0] - 钱用完了,且刚好余额为0,不需要兑换了 -> 0
// [arr.length][>0] - 钱用完了,但余额还有剩余,这种兑法是错的 -> Integer.MAX_VALUE表示错误
// [][0] - 钱没用完,但是余额已经正好为0,兑换结束 -> 0
for (int i = 0; i < dp.length; i++) {
dp[i][0] = 0;
}
// 状态转移方程:考虑当前币值用n(0 ~ j/arr[i])次 - dp[i][j] = Math.min(n + dp[i + 1][j - n*arr[i]])
// i - 从下(大)往上(小)推
// j - 从左(小)往右(大)推
for (int i = arr.length - 1; i >= 0; i--) {
for (int j = 1; j < dp[0].length; j++) {
int n = j / arr[i];
int min = Integer.MAX_VALUE;
for (int k = 0; k <= n; k++) {
int cur = dp[i + 1][j - k * arr[i]];
if (cur != Integer.MAX_VALUE) {
cur += k;
}
if (cur < min) {
min = cur;
}
}
dp[i][j] = min;
}
}
// int result = process(arr, 0, aim);
int result = dp[0][aim];
if (result == Integer.MAX_VALUE) {
return -1;
} else {
return result;
}
}
// 如果对递归方程没思路,可将以下【递归回溯】改写成【动态规划】:
// 1.递归出口 -> 初始化条件
// 2.递归分支 -> 状态转移方程
// public int process (int[] arr, int i, int j) {
// // 递归出口
// if (i == arr.length) {
// if (j == 0) {
// // 刚好到达j,算作是一个货币数目
// return 0;
// } else {
// // 无效情况
// return Integer.MAX_VALUE;
// }
// }
// if (j == 0) {
// return 0;
// }
// // 递归分支
// // 考虑当前币种用几张
// int min = Integer.MAX_VALUE;
// for (int m = 0; m <= j / arr[i]; m++) {
// // 本币值用m张
// // 后续情况
// int next = Math.min(Integer.MAX_VALUE, process(arr, i + 1, j - m * arr[i]));
// // 检验有效性,加上本货币使用个数
// int cur = Integer.MAX_VALUE;
// if (next != Integer.MAX_VALUE) {
// // 有效
// cur = next + m;
// }
// if (cur < min) {
// min = cur;
// }
// }
// return min;
// }
}
