这道题自己不会解,被困扰过很久,甚至知道了要用动态规划也没思路
本题有两种常用解法:
1. 动态规划
dp[i]代表总额为i的最少金币数量,最终解为dp[amount]
2. Recursion with Memory
按照跳台阶题目的相同思路,加到amount的最后一步只有coins.length种情况,只能是amount-coins[i]的coinChange() + 1,然后问题变为求到amount-coins[i]的最少硬币
动态规划更好,亲测时间空间效率都更高
/**
* recursion + mem 的方法
*/
class Solution {
public int coinChange(int[] coins, int amount) {
int[] mem = new int[amount + 1];
return helper(coins, mem, amount);
}
private int helper(int[] coins, int[] mem, int amount) {
if (amount == 0)
return 0;
if (mem[amount] != 0)
return mem[amount];
int min = Integer.MAX_VALUE;
for (int coin : coins) {
int target = amount - coin;
if (target < 0 || mem[target] == -1)
continue;
if (mem[target] == 0)
mem[target] = helper(coins, mem, target);
if (mem[target] != -1)
min = Math.min(mem[target] + 1, min);
}
mem[amount] = min == Integer.MAX_VALUE ? -1 : min;
return mem[amount];
}
}
/**
* 动态规划
* Runtime: 11 ms, faster than 83.09%
* Memory Usage: 38.2 MB, less than 70.95%
*/
class Solution {
public int coinChange(int[] coins, int amount) {
int[] dp = new int[amount + 1];
for (int i = 1; i <= amount; i++) {
int min = Integer.MAX_VALUE;
for (int coin : coins) {
int target = i - coin;
if (target >= 0 && dp[target] != -1)
min = Math.min(min, dp[target]);
}
dp[i] = min == Integer.MAX_VALUE ? -1 : min + 1;
}
return dp[amount];
}
}
第二次做:
/**
* Runtime: 13 ms, faster than 55.66%
* Memory Usage: 38.1 MB, less than 80.60%
*/
class Solution {
public int coinChange(int[] coins, int amount) {
int[] dp = new int[amount + 1];
for (int i = 1; i <= amount; i++) {
dp[i] = -1;
for (int val : coins) {
if (i >= val && dp[i - val] != -1) {
dp[i] = dp[i] == -1 ? dp[i - val] + 1 : Math.min(dp[i], dp[i - val] + 1);
}
}
}
return dp[amount];
}
}