LeetCode 322:零錢兌換(動態規劃)

LeetCode 322:零錢兌換(動態規劃)

給定不同面額的硬幣 coins 和一個總金額 amount。編寫一個函數來計算可以湊成總金額所需的最少的硬幣個數。如果沒有任何一種硬幣組合能組成總金額,返回 -1。

示例 1:

輸入: coins = [1, 2, 5], amount = 11
輸出: 3
解釋: 11 = 5 + 5 + 1
示例 2:

輸入: coins = [2], amount = 3
輸出: -1
說明:
你可以認爲每種硬幣的數量是無限的。

dp解法:

**思路:**dp[N] = MIN{dp[N-coins[0], dp[N-coins[1]],…dp[N-coins[N]] }+1;

int coinChange(vector<int>& coins, int amount) {
       long dp[amount+1] ={INT_MAX};
       dp[0] = 0;
       for(int i = 1; i < amount + 1 ; i++) {
            dp[i] = INT_MAX;
            for(int j = 0; j < coins.size(); j++) {
                if(i >= coins[j]) {
                    dp[i] = min(dp[i], (dp[i - coins[j]] + 1));
                }
            } 
       }
       return dp[amount] == INT_MAX ? -1 : dp[amount] ;
}
另一種更快的解法

先將硬幣面額從大到小排序, 再從最大面額的個數開始分支。即先考慮用n個最大面額硬幣, 剩餘金額在用剩餘面額硬幣兌換; 再考慮用n-1個最大面額硬幣, 剩餘金額在用剩餘面額硬幣兌換…依次類推。再進行剪枝, 若已用數量已大於最小數量, 則無續再往下討論。

int coinChange(vector<int>& coins, int amount) {
	if (amount == 0) return 0;
	sort(coins.rbegin(), coins.rend());
	int miniAns = INT_MAX;
	coinChangeIter(coins, amount, 0, 0, miniAns);
	miniAns = (miniAns == INT_MAX) ? -1 : miniAns;
	return miniAns;
}
void coinChangeIter(vector<int>& coins, int amount, int index, int count, int& miniAns){//amount: 目標值    coins:硬幣數組   index: 有效硬幣數組範圍 count: 已使用硬幣數  miniAns: 當前最小值
	if (amount == 0){ //遍歷到最後,有解
		miniAns = count < miniAns ? count : miniAns;
		return;
	}
	if (index == coins.size())
		return; //遍歷到最後,無解
	for (int maxCoinNum = amount / coins[index]; maxCoinNum >= 0 && maxCoinNum + count < miniAns; maxCoinNum--){
		coinChangeIter(coins, amount - maxCoinNum * coins[index], index + 1, count + maxCoinNum, miniAns);
	}
}
自己的再版(31% 18%)
int coinChange(vector<int>& coins, int amount) {
    if (amount == 0) return 0;
    sort(coins.begin(), coins.end());
    if (amount < coins[0]) return -1;
    vector<int> res(amount + 1, INT_MAX); res[0] = 0;

    for (int i = coins[0]; i < amount + 1; i++) {
        int minvalue = res[i - coins[0]];
        for (int j = 0; j < coins.size(); j++) {
            if (i - coins[j] >= 0 && res[i - coins[j]] < minvalue)
                minvalue = res[i - coins[j]];
        }
        if (minvalue != INT_MAX)
            res[i] = 1 + minvalue;
    }
    return res[amount] == INT_MAX ? -1 : res[amount];
}
自己的初版(時空複雜度墊底5%,5%)
int coinChange(vector<int>& coins, int amount) {
    if(amount==0) return 0;
    sort(coins.begin(), coins.end());
    if (amount < coins[0]) return -1;
    vector<int> res(amount + 1, INT_MAX); res[0] = 0;
    
    for (int i = coins[0]; i < amount + 1; i++) {
        vector<int> findmin;
        for (int j = 0; j < coins.size(); j++) {
            if (i - coins[j] >= 0) findmin.push_back(res[i - coins[j]]);
        }
        if (findmin.size() != 0) {
            int minvalue = *min_element(findmin.begin(), findmin.end());
            if (minvalue != INT_MAX)
                res[i] = 1 + minvalue;
        }
    }
    return res[amount] == INT_MAX ? -1 : res[amount];
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章