【力扣-背包】5、零钱兑换I(322)

186 阅读2分钟

「这是我参与2022首次更文挑战的第8天,活动详情查看:2022首次更文挑战」。

322. 零钱兑换

题目描述

给你一个整数数组 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

解析

/**
 * @brief 动态规划 - 背包
 *  1、确定dp数组以及下标含义
 *      dp[j]: 凑够金额为 j 时所需要金币数量最少个数为 dp[j]。
 *  2、确定递推公式
 *      凑够金额为 j - coins[i] 的最少金币个数为 dp[j- coins[i]] .
 *      那么再加上一个金币 coins[i]即 dp[j-coins[i]]+1 就可以得到凑够金金额为 j 的金币的个数
 *      此时需要考虑两种情况:dp[j]和dp[j-coins[i]]+1,所需要的是其中较小的值。
 *      所以 dp[j] = min(dp[j],dp[j-coins[i]]+1)
 *  3、初始化dp数组
 *      dp[0] = 0 : 凑够金额为0的最少金币数 , 作为dp数组的基础。
 *  4、确定遍历顺序
 *      求组合数就是:先遍历物品,再遍历背包
 *      求排列数就是:先遍历背包,再遍历物品
 *      本题要求组合数,所以选择先遍历物品,再遍历背包。
 */

代码

class Solution
{
public:
    int coinChange(vector<int> &coins, int amount)
    {
        // 考虑到递推公式的特性,将dp数组初始化为最大整数值
        vector<int> dp(amount + 1, INT32_MAX);
        // dp[0]再初始化为0
        dp[0] = 0; 
        
        // 求组合数
        // 先遍历物品
        for (int i = 0; i < coins.size(); i++)
        {
            // 再遍历背包
            for (int j = coins[i]; j <= amount; j++)
            {
                if (dp[j - coins[i]]!=INT32_MAX){
                    // 递推公式
                    dp[j] = min(dp[j], dp[j - coins[i]] + 1);
                }
            }
        }
        if(dp[amount] == INT32_MAX){
            return -1;
        }
        return dp[amount];
    }
}