1、题目:
leetcode_322_零钱兑换:https://leetcode-cn.com/problems/coin-change/
给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。
示例 1:
输入: coins = [1, 2, 5], amount = 11
输出: 3
解释: 11 = 5 + 5 + 1
示例 2:
输入: coins = [2], amount = 3
输出: -1
2、思路:
求最有解,动态规划解决。
3、代码:
解法1:暴力递归,超时,时间复杂度o(n^2)
class Solution { public int coinChange(int[] coins, int amount) { if(amount==0) return 0; int result = coinChange1(coins, amount); if(result==Integer.MAX_VALUE){ return -1; }else{ return result; } } public static int coinChange1(int[] coins, int amount) { if (coins == null || amount < 1) { return Integer.MAX_VALUE; } for (int coin : coins) { if (coin == amount) { return 1; } } int min = Integer.MAX_VALUE; for (int coin : coins) { min = Math.min(coinChange1(coins, amount - coin), min); } if (min == Integer.MAX_VALUE) { return Integer.MAX_VALUE; } else { return min + 1; } } }
解法2:动态规划
(1)定义状态:假设dp(n)是凑到n分需要的最少硬币个数
(2)求递推式:
如果第 1 次选择了 25 分的硬币,那么 dp(n) = dp(n – 25) + 1
如果第 1 次选择了 20 分的硬币,那么 dp(n) = dp(n – 20) + 1
如果第 1 次选择了 5 分的硬币,那么 dp(n) = dp(n – 5) + 1
如果第 1 次选择了 1 分的硬币,那么 dp(n) = dp(n – 1) + 1
所以 dp(n) = min { dp(n – 25), dp(n – 20), dp(n – 5), dp(n – 1) } + 1
初始状态:
dp[0]=0
所有dp[i]都初始化为Integer.MAX_VALUE
public static int coinChange(int[] coins, int amount) { if (coins == null || coins.length == 0) { return -1; } int[] dp = new int[amount + 1]; for (int i = 1; i < amount + 1; i++) { int min = Integer.MAX_VALUE; for (int j = 0; j < coins.length; j++) { if (i < coins[j] || dp[i - coins[j]] == -1) { continue; } if (i - coins[j] >= 0) { min = Math.min(min, dp[i - coins[j]]); } } if (min == Integer.MAX_VALUE) { dp[i] = -1; } else { dp[i] = min + 1; } } return dp[amount]; }
..