Java实现如下:
public class Solution { public int coinChange(int[] coins, int amount) { if (amount == 0) return 0; int[] dp = new int[amount + 1]; dp[0] = 0; for (int i = 1;i <= amount ;i++ ) { dp[i] = Integer.MAX_VALUE; for(int k :coins) { if(i>=k && dp[i-k] != Integer.MAX_VALUE) { dp[i] = Math.min(dp[i-k] + 1,dp[i]); } } } if(dp[amount]<Integer.MAX_VALUE && dp[amount] > 0) { return dp[amount]; } else { return -1; } } }
Java第二种实现:
1 class Solution { 2 public int coinChange(int[] coins, int amount) { 3 int[] dp = new int[amount+1]; 4 dp[0] = 0; 5 for(int i=1;i<amount+1;i++){ 6 dp[i] = amount + 1; 7 } 8 9 for(int i=1;i<amount+1;i++){ 10 int minNumber = amount + 1; 11 for(int coin : coins){ 12 int preIndex = i-coin; 13 if(preIndex<0){ 14 continue; 15 }else{ 16 minNumber = Math.min(minNumber,dp[preIndex]); 17 } 18 } 19 dp[i] = minNumber + 1; 20 } 21 return dp[amount] >= amount + 1 ? -1 : dp[amount]; 22 } 23 }
补充一个python的实现:
1 import sys 2 class Solution: 3 def coinChange(self, coins: 'List[int]', amount: int) -> int: 4 dp = [sys.maxsize for i in range(amount+1)] 5 dp[0] = 0 6 for i in range(1,amount+1): 7 for k in coins: 8 if i >= k and dp[i-k] != sys.maxsize: 9 dp[i] = min(dp[i],dp[i-k]+1) 10 11 return -1 if dp[amount] == sys.maxsize else dp[amount]
注意内层循环范围是coins,而不要使用range(amount+1),否则会TLE。DP方案执行时间:1700ms。
补充另一种解法,BFS + memo,效率要高一些,执行时间:1000ms。
1 class Solution: 2 def coinChange(self, coins: 'List[int]', amount: int) -> int: 3 n = len(coins) 4 if amount == 0: 5 return 0 6 target = {amount} 7 memo = set() 8 level = 0 9 result = amount + 1 10 while target: 11 cur = set() 12 for t in target: 13 if t not in memo: 14 memo.add(t) 15 for c in coins: 16 if t - c == 0: 17 result = min(result,level + 1) 18 #return level + 1 19 if t - c > 0: 20 cur.add(t - c) 21 target = cur 22 level += 1 23 return -1 if result > amount else result
思路,使用memo记录已经“扩展”的节点,之后再遇到同样数值的节点,就不再扩展了(二叉树剪枝)。
target中存储当前层的节点,cur记录下一层的节点。
注意第16行,t - c == 0时,说明发现一种可以满足要求的方案,此时记录当前树的高度,并更新result。result中保存全局最小的满足条件的树的高度值。