代码随想录day38|完全背包518零钱兑换II377组合总和IV|01笔记

95 阅读1分钟
  • 完全背包

  • 代码随想录 (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]
        }