518. 零钱兑换 II
思路
完全背包问题,相比0-1背包,内层循环遍历方式为正向遍历即可。
思路代码
func change(amount int, coins []int) int {
dp:=make([]int,amount+1)
dp[0]=1
for i:=0;i<len(coins);i++{
for j:=coins[i];j<=amount;j++{
dp[j]=dp[j]+dp[j-coins[i]]
}
}
return dp[amount]
}
377. 组合总和 Ⅳ
思路
组合的每种排列都是不同结果,那么实际上是求排列问题
外层循环表示背包
思路代码
func combinationSum4(nums []int, target int) int {
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]+dp[j-nums[i]]
}
}
}
return dp[target]
}
官方题解
个数可以不限使用,说明这是一个完全背包。
得到的集合是排列,说明需要考虑元素之间的顺序。
本题要求的是排列,那么这个for循环嵌套的顺序可以有说法了。
在动态规划:518.零钱兑换II (opens new window)中就已经讲过了。
如果求组合数就是外层for循环遍历物品,内层for遍历背包。
如果求排列数就是外层for遍历背包,内层for循环遍历物品。
如果把遍历nums(物品)放在外循环,遍历target的作为内循环的话,举一个例子:计算dp[4]的时候,结果集只有 {1,3} 这样的集合,不会有{3,1}这样的集合,因为nums遍历放在外层,3只能出现在1后面!
所以本题遍历顺序最终遍历顺序:target(背包)放在外循环,将nums(物品)放在内循环,内循环从前到后遍历。
今日收获
正向遍历用来求完全背包
外层循环背包用来求排列