20210610 每日一题 零钱兑换 II

题目

题目链接

代码

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

    }
};

方法一:二维动态规划

分析

设定二维数组 d p [ i ] [ j ] dp[i][j] dp[i][j] 表示使用前编号 i i i 的硬币中,可以得到总金额为 j j j 的组合数,二维数组 d p [ 0 ] [ 0 ] = 1 dp[0][0] = 1 dp[0][0]=1,其余起始值均为 0 0 0。对与编号 i i i 的硬币有选和不选两种情况:

  • 如果不选择使用编号 i i i 的硬币时,只是用前 i − 1 i-1 i1 个硬币可以得到总金额为 j j j 的组合数为: d p [ i ] [ j ] = d p [ i − 1 ] [ j ] dp[i][j]=dp[i-1][j] dp[i][j]=dp[i1][j]
  • 如果选择使用编号 i i i 的硬币时,由于硬币可以重复使用,设定可以使用 k k k 个编号 i i i 的硬币,则可以得到总金额为 j j j 的组合数为: d p [ i ] [ j ] = d p [ i − 1 ] [ j ] + d p [ i − 1 ] [ j − k × c o i n s [ i ] ] dp[i][j] = dp[i-1][j] + dp[i-1][j-k\times coins[i]] dp[i][j]=dp[i1][j]+dp[i1][jk×coins[i]]
    综上所述 d p [ i ] [ j ] dp[i][j] dp[i][j] 的状态转移方程可表示为:
    d p [ i ] [ j ] = { d p [ i ] [ j ] = d p [ i − 1 ] [ j ] + d p [ i − 1 ] [ j − k × c o i n s [ i ] ] i f   j ≥ k × c o i n s [ i ]   &   k ∈ N ∗ d p [ i ] [ j ] = d p [ i − 1 ] [ j ] o t h e r s dp[i][j] = \begin{cases} dp[i][j]=dp[i-1][j] + dp[i-1][j-k\times coins[i]] &if\ j \geq k\times coins[i]\ \&\ k \in N^*\\ dp[i][j] = dp[i-1][j] &others \end{cases} dp[i][j]={dp[i][j]=dp[i1][j]+dp[i1][jk×coins[i]]dp[i][j]=dp[i1][j]if jk×coins[i] & kNothers d p [ n ] [ a m o u n t ] dp[n][amount] dp[n][amount] 即为问题答案。

要点

该题目属于组合问题,硬币可重复使用

代码

class Solution {
public:
    int change(int amount, vector<int>& coins) {
        int n = coins.size();
        vector<vector<int>> dp (n + 1, vector<int>(amount + 1));
        dp[0][0] = 1;
        for(int i = 1; i <= n; ++i) {
            for(int j = 0; j <= amount; ++j) {
                dp[i][j] = dp[i - 1][j];
                for (int k = 1; k * coins[i - 1] <= j; k++) {
                    dp[i][j] += dp[i - 1][j - k * coins[i - 1]];  
                }  
            }
        }
        return dp[n][amount];
    }
};

复杂度分析

  • 时间复杂度: O ( n × a m o u n t ) O(n \times amount) O(n×amount),其中 n n n 是硬币种类, a m o u n t amount amount 是所需总金额。
  • 空间复杂度: O ( n × a m o u n t ) O(n \times amount) O(n×amount),其中 n n n 是硬币种类, a m o u n t amount amount 是所需总金额,实现动态规划需要创建 n × a m o u n t n \times amount n×amount 的二维数组 d p dp dp

方法二:一维动态规划

分析

该题目是一道典型的组合数问题,设定一维数组 d p [ i ] dp[i] dp[i] 表示构成总金额 i i i 的硬币组合数,当 i = 0 i = 0 i=0 时,只有一种情况,即 d p [ i ] = 0 dp[i] = 0 dp[i]=0。我们可以先使用单一面值硬币 c o i n coin coin 来进行计算,依次遍历所有面值的硬币,状态转移方程可表示为:
d p [ i ] = d p [ i ] + d p [ i − c o i n ] dp[i] = dp[i] + dp[i -coin] dp[i]=dp[i]+dp[icoin] 问题答案为:
d p [ a m o u n t ] dp[amount] dp[amount]

代码

class Solution {
public:
    int change(int amount, vector<int>& coins) {
        vector<int> dp (amount + 1);
        dp[0] = 1;
        for(int& coin : coins) {
            for(int i = coin; i <= amount; ++i) {
                dp[i] += dp[i - coin];
            }
        }
        return dp[amount];
    }
};

复杂度分析

  • 时间复杂度: O ( a m o u n t × n ) O(amount \times n) O(amount×n),其中 n n n 是硬币种类, a m o u n t amount amount 是所需总金额。
  • 空间复杂度: O ( a m o u n t ) O(amount) O(amount)

拓展

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值