算法作業系列14——Coin Change

算法作業系列14

Coin Change

寫在前面

爭取一日一道算法題,大學也已經過了三年了,是時候正視一下自己的未來了。

題目

You are given coins of different denominations and a total amount of money amount. Write a function to compute the fewest number of coins that you need to make up that amount. If that amount of money cannot be made up by any combination of the coins, return -1.

Example 1:
coins = [1, 2, 5], amount = 11
return 3 (11 = 5 + 5 + 1)

Example 2:
coins = [2], amount = 3
return -1.

Note:
You may assume that you have an infinite number of each kind of coin.

思路

其實看到第一反應就是,這不是揹包問題嗎?冥思苦想之下發現自己還是沒辦法記得揹包問題怎麼寫,因此上維基查了一下,再來動手寫這道題。
其實思路很簡單,只要想出來狀態轉移方程怎麼寫,剩下的就是很短的代碼了,那我們就要想,怎麼去把這道題轉成規模更小的子問題呢?其實很簡單,對於每一個數值,只需要減去一個可以交換的硬幣面額,再遞歸求解就可以啦!具體狀態轉移方程如下:

dp(i) = min{dp(i - p(j))} j=0~n

那當你性質沖沖寫完一個遞歸代碼的時候,你會發現,超時了,爲什麼呢?我們想一下,每次遞歸都需要計算一下子問題,之前計算的結果沒有被很好地保存下來,因此超時也是家常便飯啦。
那怎麼解決呢?很簡單,空間換時間即可,我們利用for循環,從最小規模算起,利用數組保存當前面額需要的最少組合,如果不能就算成-1,每一次更大規模的問題就以之前的小規模問題求解,這樣就可以重複利用之前的結果啦。

參考代碼

class Solution {
public:
    int coinChange(vector<int>& coins, int amount) {
        if (amount == 0) {
            return 0;
        }
        vector<int> dp(amount);
        for (int i = 1; i <= amount; i++) {
            dp[i - 1] = -1;
            for (int j = 0; j < coins.size(); j++) {
                if (coins[j] <= i && dp[i - coins[j] - 1] != -1 && (dp[i - 1] == -1 || dp[i - coins[j] - 1] < dp[i - 1])) {
                    dp[i - 1] = dp[i - coins[j] - 1] + 1;
                }
            }
        }
        return dp[amount - 1];
    }
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章