-
完全背包
- 代码随想录 (programmercarl.com)
-
518零钱兑换
- 代码随想录 (programmercarl.com)、
-
第一印象
- 每一种硬币的数量有无限个,需要得到总金额,所以是完全背包问题。背包容量可以设为硬币个数。dp数组的意义可以设为
dp[j]金额总数为j时有多少种取法,上限可以到amount。计算组合数的方法可以用累加。 -
讲解观后感
- dp[j]:凑成总金额j的货币组合数为dp[j]
- 递推公式:dp[j] += dp[j - coins[i]];
- dp[0] = 1
- 在思考遍历顺序的时候,就要根据题目的要求决定了。先遍历物品再遍历背包时求得的是组合数,而先遍历背包再遍历物品求得的是排列数(固定背包和遍历物品,会先后得到不同元素开头的组合)。
-
解题代码
-
func change(amount int, coins []int) int { // 定义dp数组 dp := make([]int, amount+1) // 初始化,0大小的背包, 当然是不装任何东西了, 就是1种方法 dp[0] = 1 // 遍历顺序 // 遍历物品 for i := 0 ;i < len(coins);i++ { // 遍历背包 for j:= coins[i] ; j <= amount ;j++ { // 推导公式 dp[j] += dp[j-coins[i]] } } return dp[amount] } -
377组合总和IV
- 代码随想录 (programmercarl.com)、
-
第一印象
- 数组中的每个元素都可以使用无数次,而且有一个目标值。这是典型的完全背包问题。dp数组的含义可以是目标数为j时的排列数。
-
讲解观后感
- 与上面的零钱兑换II正好互为对照,一个是求组合数,一个是求排列数。体现在代码的不同就是遍历的顺序上,求排列就要先遍历背包,后遍历数组。这样才能把每一种顺序的组合都加到结果里。
-
解题代码
-
func combinationSum4(nums []int, target int) int { //定义dp数组 dp := make([]int, target+1) // 初始化 dp[0] = 1 // 遍历顺序, 先遍历背包,再循环遍历物品 for j:=0;j<=target;j++ { for i:=0 ;i < len(nums);i++ { if j >= nums[i] { dp[j] += dp[j-nums[i]] } } } return dp[target] }