322. Coin Change

原题链接

322. 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

示例 4:

输入:coins = [1], amount = 1
输出:1

示例 5:

输入:coins = [1], amount = 2
输出:2

问题分析

总体思路和之前讲的 518. Coin Change 2 一样,可以先去看那篇文章。

这里就说一下dp数组的默认值,注意,由于最后不能保证一定能找到某种组合(找不到返回-1),所以一开始dp数组应该默认为一个特定的值,注意到状态转移方程使用了min操作,所以这个默认值应该初始化为一个比较大的值,一开始我想直接初始化为INT_MAX,这样在最后计算完成之后,如果dp[i][j]为INT_MAX,就表示不存在相应的组合。

但是,我们又注意到状态转移方程中存在 dp[i][j-coins[i]] + 1 ,如果一开始的默认值为INT_MAX,则可能发生溢出现象,那么这里取一个什么值合适呢,注意到coins数组中的元素最小值是1,当全部使用1来组成最终的amount时,会用到amount个1,也就是说,对于任意的coins数组,最后如果存在解,那么所花硬币数一定小于amount+1,故一开始dp数组都初始化为amount+1,起到了和INT_MAX的标记作用,但是又不会造成溢出。

代码

class Solution {
public:
    int coinChange(vector<int>& coins, int amount) {
        int n = coins.size();
        vector<vector<int>> dp(n, vector<int>(amount+1, amount+1));
        //dp[i][j]表示可选硬币为0...i时,能组成j所需的最少硬币

        for(int i = 0; i < n; i++) dp[i][0] = 0;
        for(int j = 1; j <= amount; j++) {
            if(j >= coins[0] && j % coins[0] == 0) dp[0][j] = j/coins[0];
        }

        for(int i = 1; i < n; i++){
            for(int j = 1; j <= amount; j++){
                if(j >= coins[i]) dp[i][j] = min(dp[i-1][j], dp[i][j-coins[i]] + 1);
                else dp[i][j] = dp[i-1][j];
            }
        }

        return dp[n-1][amount] == amount+1 ? -1 : dp[n-1][amount];
    }
};
posted @ 2021-08-15 19:11  nullxjx  阅读(47)  评论(0编辑  收藏  举报