完全背包问题

 

518. 零钱兑换 II

难度中等238

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

 

我们可以把这个问题转化为背包问题的描述形式

有一个背包,最大容量为 amount,有一系列物品 coins,每个物品的重量为 coins[i],每个物品的数量无限。请问有多少种方法,能够把背包恰好装满

若只使用 coins 中的前 i 个硬币的面值,若想凑出金额 j,有 dp[i][j] 种凑法

dp[0][..] = 0, dp[..][0] = 1(如果凑出的目标金额为 0,那么“无为而治”就是唯一的一种凑法。)

如果你不把这第 i 个物品装入背包,也就是说你不使用 coins[i] 这个面值的硬币,那么凑出面额 j 的方法数 dp[i][j] 应该等于 dp[i-1][j],继承之前的结果。

如果你把这第 i 个物品装入了背包,也就是说你使用 coins[i] 这个面值的硬币,那么 dp[i][j] 应该等于 dp[i][j-coins[i-1]]

首先由于 i 是从 1 开始的,所以 coins 的索引是 i-1 时表示第 i 个硬币的面值。

class Solution {
   	 public int change(int amount, int[] coins) {
		 int len = coins.length;
		 int[][] dp=new int[len+1][amount+1];
		 for (int i=0;i<=len;i++)
			 dp[i][0] =1 ;
		 for(int i=1;i<=len;i++)
				for (int j=1;j<=amount;j++){
					if (j>=coins[i-1]){
						dp[i][j] =dp[i-1][j] + dp[i][j-coins[i-1]];
					}
					else
						dp[i][j] =dp[i-1][j] ;
				}
		 return dp[len][amount];
	 }
}

优化:

将二维数组压缩成一维数组 DP 公式为 amount = x: dp[x] = dp[x] + dp[x - coin],dp[0] = 1;

不同于01背包的是 dp[i][j] =dp[i-1][j] + dp[i][j-coins[i-1]];
需要已经更新的dp[i][j-coins[i-1]]。那么遍历的时候就可以从前往后遍历

class Solution {
  public int change(int amount, int[] coins) {
    int[] dp = new int[amount + 1];
    dp[0] = 1;

    for (int coin : coins) {
      for (int x = coin; x < amount + 1; ++x) {
        dp[x] += dp[x - coin];
      }
    }
    return dp[amount];
  }
}

参考链接:
https://leetcode-cn.com/problems/coin-change-2/solution/dong-tai-gui-hua-wan-quan-bei-bao-wen-ti-by-liweiw/
labuladong的算法小抄: https://labuladong.gitbook.io/algo/dong-tai-gui-hua-xi-lie/bei-bao-ling-qian

 

背包九讲 :https://raw.githubusercontent.com/tianyicui/pack/master/V2.pdf

 

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值