零钱兑换2【DP】

题目

给定不同面额的硬币和一个总金额。写出函数来计算可以凑成总金额的硬币组合数。假设每一种面额的硬币有无限个。

示例 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

你可以假设:

0 <= amount (总金额) <= 5000
1 <= coin (硬币面额) <= 5000
硬币种类不超过 500 种
结果符合 32 位符号整数

解题

这道DP题有两个思路:

1.这个题要的是给了硬币面值a1,a2,a3,...由给定的硬币组合成总金额的组合数,这个和爬楼梯很像,不过可以把爬楼梯看作是给定了两个固定的台阶数,1阶,2阶,问由给定的两种台阶数组合成总台阶数的排列数。

2.这是一个完全背包,给定了包的容量amount,以及n个物品,每个物品的重量是coins[i],每个物品的数量无限,问最多存在几种能够恰好装满背包的方法。

思路1:

一维dp,改变循环顺序,组合数变成求排列数,排列数变成求组合数

(类似爬楼梯)求排列数:

class Solution {
public:

    int change(int amount, vector<int>& coins) {
        int dp[amount+100];
        dp[0] = 1;
        for(int i=1;i<amount+100;i++) dp[i] = 0;
        
        for(int i=1;i<=amount;i++)
        {
            for(int j=0;j<coins.size();j++)
        	{
                if(i<coin) continue;
                dp[i] = dp[i] + dp[i-coin[j]];
            }
        }
        return dp[amount];
    }
};

本题是求组合数,更换上面的循环顺序:

class Solution {
public:

    int change(int amount, vector<int>& coins) {
        int dp[amount+100];
        dp[0] = 1;
        for(int i=1;i<amount+100;i++) dp[i] = 0;
        
        for(int j=0;j<coins.size();j++)
        {
            int coin = coins[j];
            for(int i=1;i<=amount;i++)
            {
                if(i<coin) continue;
                dp[i] = dp[i] + dp[i-coin];
            }
        }
        return dp[amount];
    }
};
思路2:

base case:

\(dp[0][\cdot]\)= 0 如果不使用任何硬币面值,就无法凑出任何金额,即0种凑法 和 \(dp[\cdot][0]\)= 1 (dp[0][0]=1) 如果要凑出的目标金额为 0,那么有唯一的一种凑法

选择和状态:

1.选择: 装进背包 或 不装进背包

2.状态: 背包的容量 和 可选择的物品(有两个状态,所以dp用一个二维数组)

状态转移

\(\bullet\) 如果把第i个物品装入背包(即使用coins[i]这个面值的硬币),此时凑法dp[i][j]=dp[i][j-coins[i-1]] ;j-coins[i-1]表示当前背包的容量j减去当前i的重量coins[i-1];

\(\bullet\) (因为i是从 1 开始的,所以coins的索引为i-1时表示第i个硬币的面值)
如果不把第i个物品装入背包(即不使用coins[i]这个面值的硬币),此时凑法为dp[i][j]= dp[i-1][j],表示和之前状态的结果一样。

// 当选择的第i个硬币的金额比想凑的金额大时,即只有选择不装
if (j - coins[i - 1] < 0) {
    dp[i][j] = dp[i - 1][j];
} else {
    // 我们要求的dp[i][j]是共有多少种凑法,所以dp[i][j]的值应该是以上两种选择的结果之和,dp[i][j] = 不装 + 装
    dp[i][j] = dp[i - 1][j] + dp[i][j - coins[i - 1]];
}
posted @ 2020-10-03 13:56  从前有座山,山上  阅读(174)  评论(0编辑  收藏  举报