題目來源:https://leetcode.cn/problems/coin-change/description/
?C++題解(來源代碼隨想錄):題目中說每種硬幣的數量是無限的,可以看出是典型的完全背包問題。動規五部曲分析如下:
- 確定dp數組以及下標的含義。dp[j]:湊足總額為j所需錢幣的最少個數為dp[j]
- 確定遞推公式。湊足總額為j - coins[i]的最少個數為dp[j - coins[i]],那么只需要加上一個錢幣coins[i]即dp[j - coins[i]] + 1就是dp[j]。遞推公式:dp[j] = min(dp[j - coins[i]] + 1, dp[j]);
- dp數組如何初始化。首先湊足總金額為0所需錢幣的個數一定是0,那么dp[0] = 0; 其他下標對應的數值呢?考慮到遞推公式的特性,dp[j]必須初始化為一個最大的數,否則就會在min(dp[j - coins[i]] + 1, dp[j])比較的過程中被初始值覆蓋。所以下標非0的元素都是應該是最大值。
- 確定遍歷順序。本題求錢幣最小個數,那么錢幣有順序和沒有順序都可以,都不影響錢幣的最小個數。
- 舉例推導dp數組
class Solution {
public:int coinChange(vector<int>& coins, int amount) {vector<int> dp(amount + 1, INT_MAX);dp[0] = 0;for (int i = 0; i < coins.size(); i++) { // 遍歷物品for (int j = coins[i]; j <= amount; j++) { // 遍歷背包if (dp[j - coins[i]] != INT_MAX) { // 如果dp[j - coins[i]]是初始值則跳過,不跳過+1會超出int范圍。dp[j] = min(dp[j - coins[i]] + 1, dp[j]);}}}if (dp[amount] == INT_MAX) return -1;return dp[amount];}
};