1 public class Main {
2
3 /**
4 * 假设有面值1、5、10、21和25分的硬币,找出63分钱,最少用几枚硬币
5 * 用递归来解决 K 分钱的找零问题:
6 * (1)如果可以用一个硬币找零,这就是最少的
7 * (2)否则,对于每个可能的值i,我们可以独立计算找 i 分钱零钱和 K - i 分钱需要的最少硬币数, 然后选择使两者之和最小的i.
8 * @param coins 硬币面值数组
9 * @param change 需要找的钱
10 * @return
11 */
12 public static int makeChange(int[] coins, int change){
13
14 int minCoins = change; //最坏的情况时全部用 1 分 的硬币
15
16 for (int i = 0; i < coins.length; i++) {
17 if (coins[i] == change) {
18 return 1; /* 存在刚好匹配的硬币 返回 1 */
19 }
20 }
21
22 for(int j = 1; j <= change/2; j++){
23 int thisCoins = makeChange(coins, j) +
24 makeChange(coins, change-j);
25
26 if (thisCoins < minCoins) {
27 minCoins = thisCoins;
28 }
29 }
30
31 return minCoins;
32 }
33 /**
34 *
35 * 动态规划的基本思想是将待求解问题分解成 若干个子问题 ,先求解子问题,并将这些子问题的解保存起来,
36 * 如果以后在求解较大子问题的时候需要用到这些子问题的解,
37 * 就可以直接取出这些已经计算过的解而免去重复运算。保存子问题的解可以使用填表方式,例如保存在数组中
38 *
39 * 比如求解10分钱的找零, 因为在这之前 1~9 分钱的找零问题已经解决, 把 10分钱的找零分为
40 * 1 + 9, 5 + 5, 10 + 0,,每个子问题必须包含新的硬币面值,因为只有 加入新的面值,才有可能出现硬币最少的找零方式。
41 * 如果不包含新的面值 ,比如 对于找零 5
42 * 1 + 4 与 2 + 3 是一样的。对于找零 10 ,我们要考虑1加进去的找零方式 ,5加进去的找零方式,10加进去的找零方式。
43 *
44 * @param coins 保存硬币面值的数组
45 * @param differentCoins 面值的种类
46 * @param maxChange 需要找零的钱
47 * @param coinsUsed 记录每一个面值所对应的最小硬币数
48 * @param lastCoin 记录组成每一个面值所对应的,使其硬币数最小所加入的硬币面值
49 */
50 public static void makeChange(int[] coins, int differentCoins, int maxChange, int[] coinsUsed,
51 int[] lastCoin){
52 coinsUsed[0] = 0;
53 lastCoin[0] = 1;
54
55 for (int cents = 1; cents <= maxChange; cents++) {
56 int minCoins = cents;
57 int newCoin = 1;
58
59 for (int j = 0; j < differentCoins; j++) {
60 if (coins[j] > cents) {
61 continue;
62 }
63 if (coinsUsed[cents - coins[j]] + 1 < minCoins) {
64 minCoins = coinsUsed[cents-coins[j]] + 1;
65 newCoin = coins[j];
66 }
67 }
68
69 coinsUsed[cents] = minCoins;
70 lastCoin[cents] = newCoin;
71 System.out.println("找零 " + cents + " 分" + "至少需要 " + coinsUsed[cents] + " 枚硬币");
72 System.out.println("新加入的硬币是: " + lastCoin[cents] );
73 }
74 }
75
76
77 public static void main(String[] args) {
78 int[] coins = {1,5,10,21,25};
79 int maxChange = 10;
80 int[] coinsUsed = new int[maxChange+1];
81 int[] lastCoin = new int[maxChange+1];
82
83 int differentCoins = 5;
84
85 makeChange(coins, differentCoins, maxChange, coinsUsed, lastCoin);
86
87 }
88 }