关于二维数组的空间压缩问题(滚动数组):
当我们使用二维数组时,dp数组为—— dp[i][j] = max(dp[i-1],dp[i-1][j-weight[i]] + value[i]),dp[i][j]的含义是从0-i个物品中选择能装入容量为j的最大物品价值。
其中分为两种情况
- 当不选择当前物品时,那么dp[i]的价值就是前一个物品的价值
- 当选择当前物品时,dp[i]的价值就是容量为j-weight[i]的背包可装入的最大价值再加上当前物品的价值
由该二维数组的公式可以推出每一次的最大价值都是由上一次——也就是dp[i-1]决定的,故此处可考虑省去二维,降为一维。
可得此时的一维数组的递推公式为:
dp[j] = max(dp[j],dp[j-weight[i]] + value[i])
为了再循环推导的过程中使得后面的值不会被前面的值覆盖,那么就需要从后往前遍历——即背包的容量从大往小遍历。
总结:实际上dp[j]代表的就是每一列(即每一种背包的最大价值)
解释:
weight | value | |
1 | 1 | 15 |
2 | 3 | 20 |
3 | 4 | 30 |
dp[i][j] | 0 | 1 | 2 | 3 | 4 |
物品1 | 0 | 15 | 15 | 15 | 15 |
物品2 | 0 | 15 | 15 | 20 | 35 |
物品3 | 0 | 15 | 15 | 20 | 35 |
这是对应着二维数组
若是一维数组——则应如下图所示👇
下面分情况讨论几种不同的顺序导致的dp数组的不同错法:
- 正常写法(从右往左遍历)
i=0 dp[j]
0 | 1 | 2 | 3 | 4 |
0 | 15 | 15 | 15 | 15 |
- 错误写法(从左往右遍历)
i=0 dp[j]
0 | 1 | 2 | 3 | 4 |
0 | 15 | 30 | 45 | 60 |
这种顺序会累加前面算过的值
- 错误写法(背包容量循环在外层,物品循环在内层)
j=0 dp[j]
这种写法每次只能遍历一个物品,相当于背包中有且仅有一个物品!!
综上证明:
外层循环是物品,内层是背包容量,且按照从大到小顺序推导。
(注:本文部分内容参考公众号:代码随想录)