题目描述

题解
// 递归搜索
// 时间复杂度太高
class Solution {
int res = Integer.MAX_VALUE
public int coinChange(int[] coins, int amount) {
search(coins, amount, 0)
if (res == Integer.MAX_VALUE)
return -1
return res
}
public void search(int[] coins, int amount, int count) {
if (amount < 0)
return
if (amount == 0)
res = Math.min(res, count)
for (int i = 0
search(coins, amount - coins[i], count + 1)
}
}
}
// 动态规划
//
// 创建动态规划数组dp,dp[i]表示组成i金额的最少硬币数。我们要求dp[amount],
// 所以dp长度为amount + 1,所以组成金额0的硬币数为dp[0]=0。
// 在此之前,初始化dp其他位置(不要初始化为Integer.MAX_VALUE,会溢出),
// 硬币最少面额是1,所以要组成amount金额的最大硬币数就等于amount,
// 所以amount+1是一个永远到不了的数字,我们就初始化为dp的其他位置为amount+1,
//
// 要求组成i金额的最少硬币数dp[i],dp[i]就等于上一次组成金额的最少硬币数
// dp[?]加1,假设 ? 还差一枚硬币coins[j]就得到i,根据金额关系我们有:
// dp[?] = dp[i - coins[j]]。所以有:
// dp[i] = dp[i - coins[j]] + 1
// 因为要最少的硬币数,所以贪心地取最小值更新dp[i]:
// dp[i] = Math.min(dp[i], dp[i - coins[j]] + 1)
// 我们要求dp[i],就要求i之前的所有状态,所以i有for(i = 0
// 硬币能用无限次,所以coins[j]要在第二层for循环中反复取coins元素,
// j有:for(j = 0
//
// for循环从0到amount遍历dp的索引,记为i,
// 遍历每个状态组成i金额的最少硬币数为dp[i],因为硬币数量是无限的,
// 所以第二层for循环,我们从头到尾遍历coins元素记为coins[j],
// 如果coins[j]小于i,则coins[j]可以用来凑i金额,dp[i]状态由
// dp[i]和dp[i - coins[j]] + 1中的最小值决定,
// 最后遍历完之后查看dp[amount]是否大于amount,如果大于则直接返回-1,
// 否则返回dp[amount]
//
// 执行用时:16 ms, 在所有 Java 提交中击败了59.99%的用户
// 内存消耗:37.9 M, 在所有 Java 提交中击败了49.30%的用户
//
class Solution {
public int coinChange(int[] coins, int amount) {
int max = amount + 1
int[] dp = new int[amount + 1]
Arrays.fill(dp, amount + 1)
dp[0] = 0
for (int i = 1
for (int j = 0
if (coins[j] <= i) {
dp[i] = Math.min(dp[i], dp[i - coins[j]] + 1)
}
}
}
return (dp[amount] > amount) ? -1 : dp[amount]
}
}