1.題目介紹
題目地址(322. 零錢兌換 - 力扣(LeetCode))
https://leetcode.cn/problems/coin-change/
題目描述
給你一個整數陣列 coins
,表示不同面額的硬幣;以及一個整數 amount
,表示總金額。
計算並返回可以湊成總金額所需的 最少的硬幣個數 。如果沒有任何一種硬幣組合能組成總金額,返回 -1
。
你可以認為每種硬幣的數量是無限的。
示例 1:
輸入:coins =[1, 2, 5]
, amount =11
輸出:3
解釋:11 = 5 + 5 + 1
示例 2:
輸入:coins =[2]
, amount =3
輸出:-1
示例 3:
輸入:coins = [1], amount = 0 輸出:0
提示:
1 <= coins.length <= 12
1 <= coins[i] <= 231 - 1
0 <= amount <= 104
2.題解
2.1 動態規劃
思路
這裡我們可以發現,我們每次選擇一種硬幣進行找零,都會從當前狀態轉移到另一種狀態,且每次有且只有選擇和不選擇兩種方式,
由於每種硬幣的數量是無限的,我們馬上就考慮這是一個完全揹包問題。
我們設定dp[i], i代表當前已找零錢總數,dp[i]的值代表達成找零錢i所用的最小錢幣數
由於我們要求的是最小值(消耗),所以這裡初始化並不能為0,而應該初始化為INT_MAX 或者 amount + 1,
這裡建議初始化amount + 1, 如果初始化為INT_MAX,那麼就有可能產生由於dp[i - j] + 1導致的越界(這裡其實是dp[i-j]根本沒有產生相應的組合,所以我們需要加一個判斷,判斷該組合確實存在!!!)
程式碼
- 語言支援:C++
C++ Code:
class Solution {
public:
int coinChange(vector<int>& coins, int amount) {
int n = coins.size();
vector<int> dp(amount + 1, INT_MAX);
dp[0] = 0;
for(int i = 1; i <= amount; i++){
for(int j : coins){
if(i >= j && dp[i - j] != INT_MAX){
dp[i] = min(dp[i], dp[i - j] + 1);
}
}
}
return dp[amount] == INT_MAX? -1 : dp[amount];
}
};
複雜度分析
令 n 為陣列長度。
- 時間複雜度:\(O(n)\)
- 空間複雜度:\(O(n)\)