题目链接: https://leetcode-cn.com/problems/coin-change/.
提供两种思路:
解法一. DP
执行用时 : 892 ms, 在所有 Python 提交中击败了77.35%的用户
内存消耗 :12.1 MB, 在所有 Python 提交中击败了33.04%的用户
class Solution(object):
def coinChange(self, coins, amount):
dp = [float('inf')] * (amount + 1)
dp[0] = 0
for i in range(1, amount + 1):
for coin in coins:
if coin > i:
continue
dp[i] = min(dp[i], dp[i-coin] + 1)
return dp[amount] if dp[amount] != float('inf') else -1
JAVA Source Code
class Solution {
public int coinChange(int[] coins, int amount) {
int[] dp = new int[amount+1];
Arrays.fill(dp, Integer.MAX_VALUE);
dp[0] = 0;
for(int i = 1; i <= amount; i++) {
for(int j = 0; j < coins.length; j++) {
if((i >= coins[j]) && (dp[i - coins[j]] != Integer.MAX_VALUE)) {
dp[i] = Math.min(dp[i], dp[i - coins[j]] + 1);
}
}
}
return (dp[amount] == Integer.MAX_VALUE) ? -1: dp[amount];
}
}
假设F(A)代表amount = A的时候其硬币组合的最小数。
F(A) = min(F(A-C0), …, F(A-Cn)) + 1
其中Ci为ith 个硬币面值。
由此可得状态转移方程。
解法二. DFS + 贪心
执行用时 : 200 ms, 在所有 Python 提交中击败了98.98%的用户
内存消耗 : 11.9 MB, 在所有 Python 提交中击败了80.87%的用户
class Solution(object):
coins = []
res = float('inf')
def coinChange(self, coins, amount):
self.coins = sorted(coins, reverse=True)
for i in range(len(self.coins)):
self.help(i, 0, amount)
return self.res if self.res != float('inf') else -1
def help(self, coin_i, coin_count, amount):
if amount == 0:
self.res = min(self.res, coin_count)
return
for i in range(coin_i, len(self.coins)):
if (self.res - coin_count) * self.coins[i] < amount: break
if self.coins[i] > amount: continue
self.help(i, coin_count + 1, amount - self.coins[i])
利用self.res记录最终值。
help中有两个剪枝方法:
- 当(目前的结果 - 当前的硬币的数量) * 可使用的硬币的最大值 < amount,直接break
- 当前的硬币面值 > amount,continue(因为coins是reverse sort)