zoukankan      html  css  js  c++  java
  • 518.零钱兑换 II

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

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

    注意:

    你可以假设:

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

    思路:

      • [0-1]背包 问题:当前考虑的物品拿或者不拿;
      • [完全]背包 问题:当前考虑的物品拿或者不拿,如果拿,只要背包能装下,就可以一直拿,直到背包装不下为止。
      • 此题:动态规划(完全背包问题),求组合数,设 dp[i][j] 表示使用前 i种硬币组成金额 j 的组合数;
      • dp[i][j] = dp[i-1][j] + dp[i][ j-coins[i] ] ,即,对于当前的硬币 coins[i] 来说,组成金额 j 有两种情况,如果不使用这个硬币 i,而是使用前 i-1个硬币组成金额 j 的组合数为 : dp[i-1][j] ,如果使用这个硬币 i,则组合数等于 : dp[i][j - coins[i] ];

              

                             注:图片来源 Liucx

      • 一个一个物品考虑,容量一点一点扩大,整个过程就是尝试和比较的过程。

      •  代码(二维矩阵):

    class Solution {
        public int change(int amount, int[] coins) {
            int n = coins.length;
            int[][] dp = new int[n + 1][amount + 1];
            dp[0][0] = 1; //当 amount = 0 时,有 1 种方案
            for(int i = 1; i <= n; i++){ // 第 i 个硬币,从下标 1 开始
                int coin = coins[i-1]; //硬币金额
                for(int j = 0; j <= amount; j++){ //背包容量从 0 慢慢扩大到 amount
                    if(j < coin) dp[i][j] = dp[i-1][j]; //当背包容量小于当前硬币金额,此硬币不用考虑
                    else dp[i][j] = dp[i-1][j] + dp[i][j-coin]; //否则,一直放当前硬币
                    }
            }
            return dp[n][amount]; // n 个硬币都放完,背包容量为 amount 的组合数
            }
    }

      •  优化,利用滚动数组进行空间压缩;

      •  代码(一维数组):

    class Solution {
        public int change(int amount, int[] coins) {
            int[] dp = new int[amount + 1];
            dp[0] = 1; //当 amount = 0 时,有 1 种方案
            for(int i = 0; i < coins.length; i++){
                int coin = coins[i]; //硬币金额
                for(int j = coin; j <= amount; j++){ //背包容量从当前硬币 coin 慢慢扩大到 amount
                    dp[j] = dp[j] + dp[j-coin];
                }
            }
            return dp[amount];
        }
    }
  • 相关阅读:
    模板复习
    [BZOJ4016][FJOI2014]最短路径树问题(dijkstra+点分治)
    Stirling数,Bell数,Catalan数,Bernoulli数
    [BZOJ2820]YY的GCD
    [BZOJ2154]Crash的数字表格
    [HAOI2011]Problem b&&[POI2007]Zap
    [BZOJ2588][SPOJ10628]Count on a tree
    [ONTAK2010]Peaks
    [HNOI2010]弹飞绵羊
    [HNOI2004]宠物收养所
  • 原文地址:https://www.cnblogs.com/luo-c/p/13949745.html
Copyright © 2011-2022 走看看