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];
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章