代码随想录笔记_动态规划_518零钱兑换II

代码随想录笔记_动态规划

    • LC518.零钱兑换II
      • 题目
      • 思路分析
      • 代码实现
      • 小结

代码随想录二刷笔记记录

LC518.零钱兑换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 位符号整数

思路分析

思路:由题可知,存在两个条件

1.硬币有无限个

2.求凑成总金额的硬币组合数

从条件1可知,本题是一个完全背包问题。

从条件2可知,本题的遍历顺序。

以示例1为例,coin[1,2,5] ,总金额: 5,则有 4 种组合。[1,1,1,1,1] , [1,2,1,1], [2,2,1] , [5]

由此,区别组合与排列, [1,2,2] [2,2,1] 是同一种组合,但以排列的角度,这是两种排列。

组合不强调元素之间的顺序排列强调元素之间的顺序

动态规划五部曲

1.确定dp数组及其下标的含义

dp[j]:表示组成总金额 j 的组合数

2.确定递推公式

由494.目标和可知,回顾求装满背包的物品组合,一般递推公式为:

dp[j] += dp[j - num[i]] 

则本题下,考虑 coin[i] 的组合总和为 dp[j] ,则 dp[j] 等于所有不考虑 coin[i] 的组合相加。即 dp[j - coin[i]] 的相加。因此公式为:

dp[j] += dp[j - coins[i]] 
//所有的 dp[j - coins[i]] 就是不考虑 coins[i]的组合总和

3.初始化

由 LC494 可知,dp[0] 是此类组合问题递推的基础,因此 dp[0] = 1

意义为:组成总金额为 0 的组合只有一个。

4.遍历顺序

以 coin = [5,1] 为例

4.1如果先遍历物品,再遍历背包。可知,每个硬币都只会被放 1 次。即代表出现[1,5] ,但不会出现 [5,1] 的情况

for(int i = 0;i < coins.length;i++){//先遍历物品
	for(int j = coins[i];j <= amount;j++){//后遍历背包容量
		dp[j] += dp[j - coins[i]];
	}
}

4.2 如果先遍历背包,再遍历物品。因为所有物品的放的次数是无限的,背包里的每个值都会遍历1和5,则会出现 [1,5] , [5,1] 的情况

for(int j = 0;j <= amount;j++){//先遍历背包容量
	for(int i = 0;i < coins.length;i++){//后遍历物品
		if(j >= coins[i]){ 
			dp[j] += dp[j - coins[i]];
			System.out.print(dp[j] + " ");
		}
	}
	System.out.println();
}

5.推演分析

代码随想录笔记_动态规划_518零钱兑换II_第1张图片

0 1 2 3 4 5
init 1 0 0 0 0 0
物品0 1 1 1 1 1 1
物品1 1 1 2 2 3 3
物品2 1 1 2 2 3 4

代码实现

完整代码实现

public int change(int amount, int[] coins) {
		//初始化
        int[] dp = new int[amount+1];
        dp[0] = 1;
        //遍历顺序
        for (int i = 0;i < coins.length;i++){//先遍历物品
            for (int j = coins[i];j <= amount;j++){//遍历背包容量
                dp[j] += dp[j - coins[i]];
                System.out.print(dp[j] + " ");
            }
            System.out.println();
        }
    }

小结

本题考察二维01背包,同样是考察 01 背包,对我们把题目的条件,转化为物品,背包容量,有一定的难度。需要找到其中的关系,将字符串数组中的元素 s 看作物品,将限制条件 m 和 n 转化为背包容量。

你可能感兴趣的:(动态规划,算法,leetcode,数据结构,java)