題目:
給定不同面額的硬幣 coins 和一個總金額 amount。編寫一個函數來計算可以湊成總金額所需的最少的硬幣個數。如果沒有任何一種硬幣組合能組成總金額,返回 -1。
示例 1:
輸入: coins = [1, 2, 5], amount = 11
輸出: 3
解釋: 11 = 5 + 5 + 1
示例 2:
輸入: coins = [2], amount = 3
輸出: -1
說明:你可以認為每種硬幣的數量是無限的。
來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/coin-change
思路:
采用動態規划思路。
定義狀態:dp[i] 表示當目標金額為 i 時, 至少需要dp[i]枚硬幣。
狀態轉移:從當前目標金額中減去不同硬幣的面額,當前目標金額會減少,所需硬幣數量會增加。
Python解法:
1 class Solution: 2 def coinChange(self, coins: List[int], amount: int) -> int: 3 dp = {} 4 dp[0] = 0 # 目標金額為0時,所需硬幣數量為0 5 for i in range(1, amount+1): # 初始化數組 6 dp[i] = amount+1 7 8 for i in range(1, amount+1): 9 for j in range(len(coins)): # 每拼湊成一定金額,都來自某種面值硬幣 10 if coins[j] <= i: # 如果當前硬幣的面額可以湊 11 dp[i] = min(dp[i], dp[i-coins[j]]+1) # 狀態轉移方程:dp[i] = min{dp[i-coins[j]]}+1 12 # 如果dp[amount]的數值沒有更新,說明不滿足coins[j] <= i,湊不出結果 13 if dp[amount] == amount+1: return -1 14 else: return dp[amount]
C++解法:
1 class Solution { 2 public: 3 int coinChange(vector<int>& coins, int amount) { 4 if(amount < 0) 5 return -1; 6 // 定義狀態:dp[i]表示當前金額為i時至少需要dp[i]個硬幣 7 vector<int> dp(amount+1, amount+1); // 由於將dp[0]包含進去了,所以共有amount+1個元素,並且dp元素的最大值都不會大於amount+1 8 dp[0] = 0; 9 for(int i = 1; i < dp.size(); i++) { 10 for(auto coin = coins.begin(); coin != coins.end(); coin++) { 11 if(i - (*coin) < 0) 12 continue; // 由於coins的元素不一定是有序的,所以后面可能會出現符合要求的硬幣 13 dp[i] = min(dp[i], dp[i-(*coin)]+1); 14 } 15 } 16 if(dp[amount] == amount + 1) 17 return -1; 18 else 19 return dp[amount]; 20 } 21 };