力扣-322. 零錢兌換

DawnTraveler發表於2024-06-24

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)\)

相關文章