完全背包和0,1背包的差别

完全背包与0,1背包的差别


完全背包与0,1背包的唯一差别在于物品是否能被复用。两种题目实现的差别也非常非常小。举例说明:
nums=[1,2,3,4,5],target=11,求用nums中任意个数字是否能组成target。
0,1背包情况:每个数字只能被用一次
状态转移方程: dp[i][j] = dp[i-1][j] || dp[i-1][j-nums[i]]
dp[i][j]代表只用前i个数字的情况下是否能组成j
完全背包情况:每个数字可以被用无限次
状态转移方程: dp[i][j] = dp[i-1][j]dp[i][j-nums[i]]
可以发现,两个状态转移方程只差一项。对于0,1背包,状态转移方程是非常好理解的,dp[i-1][j]代表不取当前的数字,对应0,1背包中的1.

完全背包的第一项与0,1背包是一样的,关键在于第二项为什么是dp[i][j-nums[i]]。虽然与0,1背包的差别只是i和i-1的区别,但其实这个区别非常关键,理解了这个区别,那么背包问题的基本原理就可以理解了。我们通过下面的dp表格来理解。

对于0,1背包,假设现在遍历的数字为2,那么dp[2][8] = dp[1][8] || dp[1][6]
在这里插入图片描述
对于完全背包,由于2可以被取多次,所以dp[2][8] = dp[1][8] || dp[1][6] || dp[1][4] || dp[1][2] || dp[1][0]
在这里插入图片描述
但是当假设背包容量无穷大而物体的体积无穷小,那么这个计算的复杂度会非常非常高。所以我们再来看下一个表。从下面的表发现dp[2][6] = || dp[1][6] || dp[1][4] || dp[1][2] || dp[1][0]. 这不就是计算dp[2][8]的时候计算的几项吗!!!
在这里插入图片描述
所以说综合上面两个表,我们可以得到下表,也就是dp[2][8] = dp[1][8] || dp[2][6].
在这里插入图片描述
这边举得例子是||操作的情况,而对于subproblem涉及到min,max,+等操作,这种关系显而易见也是成立的。下面列了几个leetcode中0,1背包和完全背包的经典题目。
0,1背包:
Leetcode 416 Partition Equal Subset Sum
Leetcode 474. Ones and Zeroes
Leetcode 494. Target Sum

完全背包:
Leetcode 322. Coin Change
Leetcode 518. Coin Change 2

关于背包问题的空间压缩优化,在这边只做一点总结,后面有机会再进行详细分析。
压缩空间时到底需要正向还是逆向遍历呢?物品和体积哪个放在外层,哪个放在内层呢?这取决于状态转移方程的依赖关系。在思考空间压缩前,不妨将状态转移矩阵画出来,方便思考如何进行空间压缩。如果您实在不想仔细思考,这里有个简单的口诀:0-1 背包对物品的迭代放在外层,里层的
体积或价值逆向遍历;完全背包对物品的迭代放在里层,外层的体积或价值正向遍历。可以参考上面几个题目的解析来对比理解,上面的题目大部分都写了空间优化和不优化的共同解法

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值