【题目描述】

给你一个整数数组 ​​coins​​​ ,表示不同面额的硬币;以及一个整数 ​​amount​​ ,表示总金额。

计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回 ​​-1​​ 。

你可以认为每种硬币的数量是无限的。

​​​​https://leetcode.cn/problems/coin-change/​

【示例】

【LeeCode】322. 零钱兑换_数组

【代码】​​递归+Hash​

【LeeCode】322. 零钱兑换_数组_02

【LeeCode】322. 零钱兑换_数组_03

package com.company;
import java.util.*;

// 2023-03-04
class Solution {
Map<Integer, Integer> map = new HashMap<>();
public int coinChange(int[] coins, int amount) {
if (map.containsKey(amount)){
return map.get(amount);
}
if (amount == 0) return 0;
if (amount < 0 ) return -1;
int res = Integer.MAX_VALUE;
for (int x : coins){
int coin = coinChange(coins, amount - x);
if (coin == -1) continue;
res = Math.min(res, coin + 1);
}
res = res == Integer.MAX_VALUE ? -1 : res;
map.put(amount, res);
return res;
}
}
public class Test {
public static void main(String[] args) {
new Solution().coinChange(new int[]{1, 2, 5}, 11); // 输出:3
new Solution().coinChange(new int[]{2}, 3); // 输出:-1
new Solution().coinChange(new int[]{1}, 0); // 输出:0
}
}

【代码】​​动态规划​

比如你想求 amount = 11 时的最少数(原问题),如果你知道凑出 amount = 10 的最少数(子问题),你只需要把子问题的答案加一(再选一枚面值为 1 的***)就是原问题的答案。因为***的数量是没有限制的,所以子问题之间没有相互制,是互相独立的。


package com.company;
import java.util.*;

// 2023-03-01
class Solution {
Map<Integer, Integer> map = new HashMap<>();
public int coinChange(int[] coins, int amount) {
// 当目标金额为 i 时,至少需要 dp[i] 枚Q凑出amount
int[] dp = new int[amount + 1];
Arrays.fill(dp, amount + 1);
// 目标金额为0,初始值为=0
dp[0] = 0;
int len = dp.length;

// 外层 for 循环在遍历所有状态的所有取值
for (int i = 0; i < len; i++){
// 内层 for 循环在求所有选择的最小值
for (int coin: coins){
// 子问题无解,跳过
if (i < coin) continue;
// amount[11] = amount[10] + 1
dp[i] = Math.min(dp[i], dp[i - coin] + 1);
}
}
System.out.println((dp[amount] == amount + 1) ? -1 : dp[amount]);
return (dp[amount] == amount + 1) ? -1 : dp[amount];
}
}
public class Test {
public static void main(String[] args) {
new Solution().coinChange(new int[]{1, 2, 5}, 11); // 输出:3
new Solution().coinChange(new int[]{2}, 3); // 输出:1
new Solution().coinChange(new int[]{1}, 0); // 输出:0
}
}


【代码】admin

通过率 30/189  这里当前主要的问题是, 如果coins的长度为1的判断不够, 

思路: 通过【回溯法】把所有可能的结果放入到res中然后获取min的list, 返回长度即可。 不研究了,动态规划吧

package com.company;
// 2023-1-6
import java.util.*;

class Solution {
List<List<Integer>> res = new LinkedList<>();
LinkedList<Integer> list = new LinkedList<>();
public int coinChange(int[] coins, int amount) {
if (coins.length == 1 && coins[0] > amount) return 0;
if (coins.length == 1 && coins[0] == amount) return 1;
if (coins.length == 1 && 2 * coins[0] > amount && coins[0] < amount) return -1;

dfs(coins, amount, 0, 0);
if (res.size() == 0) return 0;
List<Integer> integers = res.stream().min(Comparator.comparingInt(List::size)).get();
return integers.size();
}

private void dfs(int[] coins, int amount, int index, int sum) {
if (sum == amount){
res.add(new LinkedList<>(list));
return;
}

for (int i = index; i < coins.length && sum + coins[i] <= amount; i++){
sum += coins[i];
list.add(coins[i]);
dfs(coins, amount, i, sum);
sum -= coins[i];
list.removeLast();
}
}
}
public class Test {
public static void main(String[] args) {
new Solution().coinChange(new int[]{1, 2, 5}, 11); // 输出: 3 即, 11 = 5 + 5 + 1
new Solution().coinChange(new int[]{2}, 3); // 输出: -1
new Solution().coinChange(new int[]{1}, 0); // 输出: 0
}
}