-
爬楼梯(背包版)
- programmercarl.com/0070.%E7%88…
-
322零钱兑换
- 代码随想录 (programmercarl.com)
-
第一印象
- 每种硬币可以取的数目是无限的,属于完全背包问题。最少硬币数量的拿取方式什么顺序都可以,有无顺序都可以得到某种最小值。那么内外不重要。
-
讲解观后感
- 确定dp数组以及下标的含义
dp[j]:凑足总额为j所需钱币的最少个数为dp[j] - 确定递推公式
dp[j] = min(dp[j - coins[i]] + 1, dp[j]); dp[0] = 0;考虑到递推公式的特性,dp[j]必须初始化为一个最大的数,否则就会在min(dp[j - coins[i]] + 1, dp[j])比较的过程中被初始值覆盖。所以下标非0的元素都是应该是最大值。- 遍历顺序不重要,因为不管是组合还是排列,都会出现能取到的最小值。
-
解题代码
-
// 版本一, 先遍历物品,再遍历背包 func coinChange1(coins []int, amount int) int { dp := make([]int, amount+1) // 初始化dp[0] dp[0] = 0 // 初始化为math.MaxInt32 for j := 1; j <= amount; j++ { dp[j] = math.MaxInt32 } // 遍历物品 for i := 0; i < len(coins); i++ { // 遍历背包 for j := coins[i]; j <= amount; j++ { if dp[j-coins[i]] != math.MaxInt32 { // 推导公式 dp[j] = min(dp[j], dp[j-coins[i]]+1) //fmt.Println(dp,j,i) } } } // 没找到能装满背包的, 就返回-1 if dp[amount] == math.MaxInt32 { return -1 } return dp[amount] } // 版本二,先遍历背包,再遍历物品 func coinChange2(coins []int, amount int) int { dp := make([]int, amount+1) // 初始化dp[0] dp[0] = 0 // 遍历背包,从1开始 for j := 1; j <= amount; j++ { // 初始化为math.MaxInt32 dp[j] = math.MaxInt32 // 遍历物品 for i := 0; i < len(coins); i++ { if j >= coins[i] && dp[j-coins[i]] != math.MaxInt32 { // 推导公式 dp[j] = min(dp[j], dp[j-coins[i]]+1) //fmt.Println(dp) } } } // 没找到能装满背包的, 就返回-1 if dp[amount] == math.MaxInt32 { return -1 } return dp[amount] } func min(a, b int) int { if a < b { return a } return b } -
279完全平方数
- 代码随想录 (programmercarl.com)
-
第一印象
- 和为n,相当于价值目标为n,容量也为n,物品的序列就是完全平方数的序列。每个完全平方数可以使用无数次。所以是完全背包。
-
讲解观后感
- dp[j]:和为j的完全平方数的最少数量为dp[j]
- 递推公式:
dp[j] = min(dp[j - i * i] + 1, dp[j]); dp[0]=0非0下标的dp[j]一定要初始为最大值,这样dp[j]在递推的时候才不会被初始值覆盖。- 本题外层for遍历背包,内层for遍历物品,还是外层for遍历物品,内层for遍历背包,都是可以的,因为不管是组合还是排列都能得到最小值!
-
出现问题
- 问题原因:内层循环物品时有太多冗余,改正方法是将判定条件改为
i:=1;i*i<=j;i++ -
解题代码
-
// 版本一,先遍历物品, 再遍历背包 func numSquares1(n int) int { //定义 dp := make([]int, n+1) // 初始化 dp[0] = 0 for i := 1; i <= n; i++ { dp[i] = math.MaxInt32 } // 遍历物品 for i := 1; i <= n; i++ { // 遍历背包 for j := i*i; j <= n; j++ { dp[j] = min(dp[j], dp[j-i*i]+1) } } return dp[n] } // 版本二,先遍历背包, 再遍历物品 func numSquares(n int) int { //定义 dp := make([]int, n+1) // 初始化 dp[0] = 0 // 遍历背包 for j := 1; j <= n; j++ { //初始化 dp[j] = math.MaxInt32 // 遍历物品 for i := 1; i*i <= j; i++ { if j >= i*i { dp[j] = min(dp[j], dp[j-i*i]+1) } } } return dp[n] } func min(a, b int) int { if a < b { return a } return b }