【力扣-背包】4、零钱兑换II(518)

159 阅读2分钟

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

518. 零钱兑换 II

题目描述

给你一个整数数组 coins 表示不同面额的硬币,另给一个整数 amount 表示总金额。

请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0 。

假设每一种面额的硬币有无限个。 

题目数据保证结果符合 32 位带符号整数。

示例 1:

输入: amount = 5, coins = [1, 2, 5]
输出: 4
解释: 有四种方式可以凑成总金额:
5=5
5=2+2+1
5=2+1+1+1
5=1+1+1+1+1

示例 2:

输入: amount = 3, coins = [2]
输出: 0
解释: 只用面额 2 的硬币不能凑成总金额 3 。

示例 3:

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

解析

/**
 * @brief 动态规划 - 完全背包
 *  1、确定dp数组以及下标含义
 *      dp[j]: 表示凑成总金额 j 的货币组合数为 dp[j]
 *  2、确定递推公式
 *      dp[j] (考虑coins[i]的组合总数) 就是所有的dp[j-coins[i]] (不考虑 coins[i]时)相加
 *      所以递推公式为:
 *          dp[j] += dp[j-coins[i]];
 *  3、初始化dp数组
 *      首先dp[0]一定为1,dp[0] = 1 是递推公式的基础 (凑成总金额为0的货币组合数为1)
        其他dp[i]初始时默认为0
 *  4、确定递归顺序
        **组合不强调元素之间的顺序,排列强调元素之间的顺序**。
        这里需要考虑是求组合数还是求排列数
 *      先物品后背包: 求组合数
 *      先背包后物品:求排列数
 * 
 * 
 */

代码

class Solution
{
public:
    int change(int amount, vector<int> &coins)
    {

        // 定义dp数组,并进行初始化
        vector<int> dp(amount + 1, 0);
        dp[0] = 1; // 初始dp[0] ,作为基础
        
        // 求组合数
        // 先遍历物品
        for (int i = 0; i < coins.size(); i++)
        {
            // 再遍历背包
            for (int j = coins[i]; j <= amount; j++)
            {
                // 递推公式
                dp[j] += dp[j - coins[i]];
            }
        }

        return dp[amount];
    }
};