代码随想录算法训练营day42 | 01背包问题,你该了解这些!,01背包问题,你该了解这些! 滚动数组 , 416. 分割等和子集
代码随想录算法训练营day42 | 背包理论基础,背包理论基础(滚动数组), 416. 分割等和子集
- 1、01背包理论基础
- 背包问题概述
- 01背包
- 二维dp数组01背包案例
- 2、01背包理论基础(滚动数组)
- 3、 416. 分割等和子集
- 解法一:动态规划
1、01背包理论基础
教程视频:https://www.bilibili.com/video/BV1cg411g7Y6
背包问题概述
重点掌握01 背包和完全背包即可。
01背包
问题:有n件物品和一个最多能背重量为w 的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。每件物品只能用一次,求解将哪些物品装入背包里物品价值总和最大。
暴力解法:每一件物品其实只有两个状态,取或者不取,所以可以使用回溯法搜索出所有的情况,那么时间复杂度就是 o ( 2 n ) o(2^n) o(2n),这里的n表示物品数量。
因为暴力的解法是指数级别的时间复杂度。进而才需要动态规划的解法来进行优化!
二维dp数组01背包案例
背包最大重量为4。
物品为:
物品 | 重量 | 价值 |
---|---|---|
物品0 | 1 | 15 |
物品1 | 3 | 20 |
物品2 | 4 | 30 |
**每件商品都仅有一个!**问背包能背的物品最大价值是多少?
动态规划分析:
- 确定dp数组以及下标的含义
这里使用二维数组解决。即dp[i][j] 表示从下标为[0-i]的物品里任意取,放进容量为j的背包,价值总和最大是多少。
物品编号(i) \ 背包容量(j) | 0 | 1 | 2 | 3 | 4 | |
---|---|---|---|---|---|---|
物品0 | 0 | 0 | 15 | 15 | 15 | 15 |
物品1 | 1 | 0 | dp[1][1] | dp[1][2] | dp[1][3] | dp[1][4] |
物品2 | 2 | 0 | dp[2][1] | dp[2][2] | dp[2][3] | dp[2][4] |
确定递推公式
有两个方向推出来dp[i][j]:
不放物品i :由dp[i - 1][j]推出,即背包容量为j,里面不放物品i的最大价值,此时dp[i][j]就是dp[i - 1][j]。(其实就是当物品i的重量大于背包j的重量时,物品i无法放进背包中,所以被背包内的价值依然和前面相同。)在表格中表现为正上方格子值+当前行的物品价值。
放物品i:由dp[i - 1][j - weight[i]]推出,dp[i - 1][j - weight[i]] 为背包容量为j - weight[i]的时候不放物品i的最大价值,那么dp[i - 1][j - weight[i]] + value[i] (物品i的价值),就是背包放物品i得到的最大价值。因此dp[i][j]=Math.max(dp[i-1][j], dp[i-1][j-weight[i]]+value[i]);
dp数组如何初始化
背包容量为0时,最大价值为0,即dp[*][0]=0;
对第一件物品来说,背包容量不够时最大价值为0;从能放进背包那一刻开始,背包的最大价值等于value[0]。
剩余位置初始为什么数值都可以,因为都会被覆盖。确定遍历顺序
双层for循环,一层遍历物品,一层遍历背包。
在本题中,只要保持dp[<i][<=j]处都有值即可,因此两层循环顺序调换并不影响最终结果。举例推导dp数组
做动态规划的题目,最好的过程就是自己在纸上举一个例子把对应的dp数组的数值推导一下,然后再动手写代码!
class Solution{public static void main(String[] args) {int[] weight = {1,3,4};int[] value = {15,20,30};int bagSize = 4;testBagProblem(weight,value,bagSize);}public static void testBagProblem(int[] weight, int[] value, int bagSize){// 创建dp数组int[][] dp = new int[weight.length][bagSize+1];// 初始化dp数组for(int i=0;i<weight.length;i++){dp[i][0]=0;}for(int i=0;i<=bagSize;i++){if(i>=weight[0]){dp[0][i]=value[0];}dp[0][i]=0;}// 填充dp数组for(int i=1;i<weight.length;i++){for(int j=1;j<=bagSize;j++){if(j>=weight[i]){//当前背包的容量大于等于当前物品i的时候,比较两种情况下,哪种最大价值最大dp[i][j] = Math.max(dp[i-1][j], dp[i-1][j-weight[i]]+value[i]);}else{dp[i][j] = dp[i-1][j];}}}//打印for (int i = 0; i < weight.length; i++) {for (int j = 0; j <= bagSize; j++) {System.out.print(dp[i][j] + "\t");}System.out.println("\n");}}
}
2、01背包理论基础(滚动数组)
教程视频:https://www.bilibili.com/video/BV1BU4y177kY
滚动数组,其实就是将二维dp表格解决降为一维dp数组,一些录友当时还表示比较困惑。
- 确定dp数组的定义
在一维dp数组中,dp[j]表示:容量为j的背包,所背的物品价值可以最大为dp[j]。 - 一维dp数组的递推公式
dp[j] = max(dp[j], dp[j - weight[i]] + value[i]); - 一维dp数组如何初始化
下标0的位置,即dp[0]初始为0。
从递归公式可以看出,dp数组在推导的时候一定是取价值最大的数,所以如果题目给的价值都是正整数,那么非0下标都初始化为0就可以了。 - 一维dp数组遍历顺序
此时因为将对于物品的遍历压缩到一位数组中,需要先遍历物品,再遍历背包容量。
为了利用上次循环的状态,同时保证物品i只被放入一次,背包容量需要倒序遍历。 - 举例推导dp数组
class Solution{public static void main(String[] args) {int[] weight = {1,3,4};int[] value = {15,20,30};int bagSize = 4;testBagProblem(weight,value,bagSize);}public static void testBagProblem(int[] weight, int[] value,int bagSize){//定义dp数组int[] dp = new int[bagSize+1];//dp数组初始化(默认全为0,可以不显示初始化)for(int i=0;i<weight.length;i++){for(int j=bagSize;j>=0;j--){if(j>weight[i]){dp[j] = Math.max(dp[j], dp[j-weight[i]]+value[i]);}//这里可以化简,还可以把if判断放在for循环条件中//else{//dp[j]=dp[j];//}}//打印dp数组for (int j = 0; j <= bagSize; j++){System.out.print(dp[j] + " ");}}}
}
3、 416. 分割等和子集
教程视频:https://www.bilibili.com/video/BV1rt4y1N7jE
解法一:动态规划
注意题目描述中商品是不是可以重复放入。所以本题中,要使用的是01背包,因为元素只能用一次。
只有确定了如下四点,才能把01背包问题套到本题上来:
1、背包的体积为sum / 2
2、背包要放入的商品(集合里的元素)重量为 元素的数值,价值也为元素的数值
3、背包如果正好装满,说明找到了总和为 sum / 2 的子集。
4、背包中每一个元素是不可重复放入。
- 确定dp数组以及下标的含义
dp[j]表示 背包总容量(所能装的总重量)是j,放进物品后,背的最大重量为dp[j]。 - 确定递推公式(物品i的重量是nums[i],其价值也是nums[i])
dp[j]=Math.max(dp[j], dp[j-nums[i]]+nums[i]); - dp数组如何初始化
首先dp[0]是0。
题目给的价值都是正整数,所以非0下标都初始化为0。 - 确定遍历顺序
同理滚动数组,外层for循环遍历nums中数值,内层for循环反向遍历背包容量。 - 举例推导dp数组
dp[j]的数值一定是小于等于j的。
如果dp[j] == sum/2,即背包正好装满,说明集合中的子集总和正好可以凑成sum/2。
class Solution {public boolean canPartition(int[] nums) {int sum=0;for(int i=0;i<nums.length;i++){sum+=nums[i];}//总和为奇数,不能平分if(sum%2==1){return false;}int[] dp = new int[sum/2+1];for(int i=0;i<nums.length;i++){for(int j=sum/2;j>=nums[i];j--){//物品 i 的重量是 nums[i],其价值也是 nums[i]dp[j]=Math.max(dp[j], dp[j-nums[i]]+nums[i]);}}return dp[sum/2] == sum/2;}
}
代码随想录算法训练营day42 | 01背包问题,你该了解这些!,01背包问题,你该了解这些! 滚动数组 , 416. 分割等和子集相关推荐
- 代码随想录算法训练营day42 |动态规划之背包问题 11.分割等和子集 1049. 最后一块石头的重量 II 494. 目标和
day42 11.分割等和子集 1.dp数组的含义 2.确定递推公式 3.dp数组初始化 4.确定遍历顺序 5.打印dp数组 1049. 最后一块石头的重量 II 1.确定dp数组以及下标的含义 2. ...
- 代码随想录算法训练营第四十二天-动态规划4|● 01背包问题,你该了解这些! ● 01背包问题,你该了解这些! 滚动数组 ● 416. 分割等和子集
今天只有1道题,属于动态规划的01背包问题的应用.首先理解一下动态规划的01背包问题.推荐一个视频,动态规划DP0-1背包,这是我认为讲得最为通透的.很多讲解动态背包问题的,一上来就画二维表格,遍历背 ...
- 代码随想录算法训练营第四十二天 | 01背包问题,你该了解这些、01背包问题,你该了解这些 滚动数组、 416. 分割等和子集
打卡第42天,搞搞01背包. 今日任务 01背包问题,你该了解这些! 01背包问题,你该了解这些! 滚动数组 416.分割等和子集 背包问题1.0 :0-1 背包 有n件物品和一个最多能背重量为w 的 ...
- 代码随想录算法训练营day1
代码随想录算法训练营第一天| 704. 二分查找.27. 移除元素. 704.二分查找 题目链接:leetcode704 Binary search 暴力解法: class Solution {pub ...
- 代码随想录算法训练营第七天| 哈希表理论基础 ,454.四数相加II, 383. 赎金信, 15. 三数之和, 18. 四数之和
代码随想录算法训练营第七天| 哈希表理论基础 ,454.四数相加II, 383. 赎金信, 15. 三数之和, 18. 四数之和 454.四数相加II 建议:本题是 使用map 巧妙解决的问题,好好体 ...
- 代码随想录算法训练营第二天| 977.有序数组的平方 ,209.长度最小的子数组 ,59.螺旋矩阵II。
代码随想录算法训练营第二天| 977.有序数组的平方 ,209.长度最小的子数组 ,59.螺旋矩阵II. 977.有序数组的平方 209. 长度最小的子数组 59. 螺旋矩阵 II 977.有序数组的 ...
- 代码随想录算法训练营第二天 | 力扣977.有序数组的平方,209.长度最小的子数组,59.螺旋矩阵II
代码随想录算法训练营第二天 | 977.有序数组的平方 ,209.长度最小的子数组 ,59.螺旋矩阵II 977.有序数组的平方 题目链接:有序数组的平方 题目描述: 给你一个按 非递减顺序 排序的整 ...
- 代码随想录算法训练营第二天 | LeetCode977.有序数组的平方 ,209.长度最小的子数组,59.螺旋矩阵II
代码随想录算法训练营第二天 | LeetCode977.有序数组的平方 ,209.长度最小的子数组,59.螺旋矩阵II 一. LeetCode977.有序数组的平方 1. 题目链接[LeetCode9 ...
- _42LeetCode代码随想录算法训练营第四十二天-动态规划 | 121.买卖股票的最佳时机、122.买卖股票的最佳时机II
_42LeetCode代码随想录算法训练营第四十二天-动态规划 | 121.买卖股票的最佳时机.122.买卖股票的最佳时机II 题目列表 121.买卖股票的最佳时机 122.买卖股票的最佳时机II 1 ...
最新文章
- 【面试必备】javascript的原型和继承
- 版本效果MoonWarrior cocos2d-x版本 --1
- 有什么类型的MPLS?
- 各项兼容坑的记录-持续更新
- NOI Linux2.0使用系列视频集
- dnf强化卷代码_这行代码告诉你!为什么你地下城与勇士(DNF)的装备强化老是失败?...
- c编程:求出4#215;4矩阵中最大和最小元素值及其所在行下标和列下标,求出两条主对角线元素之和。...
- LeetCode 144. 树的前序遍历迭代写法
- js中自己实现each方法来遍历多维数组
- 带ant 的收发器_ANT无线收发器nRF24AP1及其应用
- 使用QFIL升级高通芯片的Android系统
- android桌面小工具,超好用的手机桌面小组件,一键美化桌面,实用又美观
- 优炫数据库收到来自重庆市统计局的感谢信
- CAN总线学习总结2——CAN错误及CAN busoff处理机制
- 物联网下的智慧停车 让智能化找到车位
- python文档学习
- 三维几何 --- 计算几何模板
- 【Java位运算】n1和n>>1含义
- 在线代码离线翻译Chrome插件一马v0.0.8 2018-10-31
- 商家联盟会员管理系统源码
热门文章
- IDEA Maven Helper插件(详细使用教程)
- SQL Father - 模拟数据生成器(后端)
- git+webhookit 在codding上 实现代码自动部署
- 新手必备pr 2021快速入门教程「四」新建序列及参数设置
- 《哪吒》飞来,国漫春天将至,互联网下国漫将如何开启崛起之路?
- oracle文件系统挂载点,oracle dbfs文件系统介绍及使用测试
- The ADO.NET provider with invariant name “MySql.Data.MySqlClient” is either not registered
- 人工智能辅助药物发现(1)肿瘤靶点识别
- Type-C PD的取电可以说诱骗、诱电、SINK
- Vue自定义动画/过渡