当前位置: 首页 > news >正文

leetcode 01背包问题

在这里插入图片描述
典型的01背包问题可以暴力求解,直接将所有可能全部遍历然后挑选符合条件的即可,但这样时间复杂度过高,有2的n次方。

所以我们在这里采用动态规划的方式来做,并且,我们可以采用二维数组或者一维数组来做。

二维数组:dp[i][j] 表示从下标为[0-i]的物品里任意取,放进容量为j的背包,价值总和最大是多少。

确定递推公式:如果不放入物品i,那么dp[i][j] = dp[i-1][j],如果放入了物品i,那么就应该是dp[i-1][j-weight[i]] + value[i]。二者直接取最大值即可。

初始化:首先我们考虑j=0的情况,此时背包任何东西都放不进去,所以就是dp[i][0]=0,之后我们考虑i=0,即放物品0的情况,只有当物品0的质量小于j的时候,才能把物品j放入,此时数组才是有值的,其他应该为0。所以我们只需要把当物品0的质量小于j的时候的值放入,其余位置全部置为0即可。

遍历顺序:二维数组解决01背包问题,先遍历物品或者背包都可以,直接从前往后遍历即可,因为每一个位置的元素是由这个元素上面位置和左上位置推导出来的(递归公式)。

打印数组:
在这里插入图片描述

public class BagProblem {public static void main(String[] args) {int[] weight = {1,3,4};int[] value = {15,20,30};int bagSize = 4;testWeightBagProblem(weight,value,bagSize);}/*** 动态规划获得结果* @param weight  物品的重量* @param value   物品的价值* @param bagSize 背包的容量*/public static void testWeightBagProblem(int[] weight, int[] value, int bagSize){// 创建dp数组int goods = weight.length;  // 获取物品的数量int[][] dp = new int[goods][bagSize + 1];//**因为背包容量可能为0,所以需要bagSize+1个数组**// 初始化dp数组// 创建数组后,其中默认的值就是0for (int j = weight[0]; j <= bagSize; j++) {dp[0][j] = value[0];}// 填充dp数组for (int i = 1; i < weight.length; i++) {//物品编号是从0开始,所以i<weight.lengthfor (int j = 1; j <= bagSize; j++) {//背包容量从1开始遍历,最大是bagSize,可以取得到if (j < weight[i]) {/*** 当前背包的容量都没有当前物品i大的时候,是不放物品i的* 那么前i-1个物品能放下的最大价值就是当前情况的最大价值*/dp[i][j] = dp[i-1][j];} else {/*** 当前背包的容量可以放下物品i* 那么此时分两种情况:*    1、不放物品i*    2、放物品i* 比较这两种情况下,哪种背包中物品的最大价值最大*/dp[i][j] = Math.max(dp[i-1][j] , dp[i-1][j-weight[i]] + value[i]);}}}// 打印dp数组for (int i = 0; i < goods; i++) {for (int j = 0; j <= bagSize; j++) {System.out.print(dp[i][j] + "\t");}System.out.println("\n");}}
}

当然本题也可以用一维数组来做
动规五部曲分析如下:

确定dp数组的定义
在一维dp数组中,dp[j]表示:容量为j的背包,所背的物品价值可以最大为dp[j]。

一维dp数组的递推公式
dp[j]为 容量为j的背包所背的最大价值,那么如何推导dp[j]呢?

dp[j]可以通过dp[j - weight[i]]推导出来,dp[j - weight[i]]表示容量为j - weight[i]的背包所背的最大价值。

dp[j - weight[i]] + value[i] 表示 容量为 j - 物品i重量 的背包 加上 物品i的价值。(也就是容量为j的背包,放入物品i了之后的价值即:dp[j])

此时dp[j]有两个选择,一个是取自己dp[j] 相当于 二维dp数组中的dp[i-1][j],即不放物品i,一个是取dp[j - weight[i]] + value[i],即放物品i,指定是取最大的,毕竟是求最大价值,

所以递归公式为:dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);

一维dp数组如何初始化
关于初始化,一定要和dp数组的定义吻合,否则到递推公式的时候就会越来越乱。

dp[j]表示:容量为j的背包,所背的物品价值可以最大为dp[j],那么dp[0]就应该是0,因为背包容量为0所背的物品的最大价值就是0。

那么dp数组除了下标0的位置,初始为0,其他下标应该初始化多少呢?

看一下递归公式:dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);

dp数组在推导的时候一定是取价值最大的数,如果题目给的价值都是正整数那么非0下标都初始化为0就可以了。

这样才能让dp数组在递归公式的过程中取的最大的价值,而不是被初始值覆盖了。

那么我假设物品价值都是大于0的,所以dp数组初始化的时候,都初始为0就可以了。

一维dp数组遍历顺序
代码如下:

for(int i = 0; i < weight.size(); i++) { // 遍历物品
for(int j = bagWeight; j >= weight[i]; j–) { // 遍历背包容量
dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);

倒序遍历是为了保证物品i只被放入一次!。但如果一旦正序遍历了,那么物品0就会被重复加入多次!

 public static void main(String[] args) {int[] weight = {1, 3, 4};int[] value = {15, 20, 30};int bagWight = 4;testWeightBagProblem(weight, value, bagWight);}public static void testWeightBagProblem(int[] weight, int[] value, int bagWeight){int wLen = weight.length;//定义dp数组:dp[j]表示背包容量为j时,能获得的最大价值int[] dp = new int[bagWeight + 1];//遍历顺序:先遍历物品,再遍历背包容量for (int i = 0; i < wLen; i++){for (int j = bagWeight; j >= weight[i]; j--){dp[j] = Math.max(dp[j], dp[j - weight[i]] + value[i]);}}//打印dp数组for (int j = 0; j <= bagWeight; j++){System.out.print(dp[j] + " ");}}

相关文章:

  • Recorder 实现语音录制并上传到后端(兼容PC和移动端)
  • unity学习(15)——服务器组装(1)
  • LeetCode 0590. N 叉树的后序遍历:深度优先搜索(DFS)
  • 课后延时服务选课报名管理系统功能清单
  • RESTful 风格是指什么
  • 1027. 最长等差数列【leetcode】/动态规划
  • 【嵌入式】CAN总线
  • 数据库管理-第151期 Oracle Vector DB AI-03(20240218)
  • 【算法】树状数组
  • 突破编程_C++_面试(变量与常量)
  • WireShark 安装指南:详细安装步骤和使用技巧
  • 算法练习-01背包问题【含递推公式推导】(思路+流程图+代码)
  • 沁恒CH32V30X学习笔记11---使用外部时钟模式2采集脉冲计数
  • PAM | 账户安全 | 管理
  • 适用于Android 的 7 大短信恢复应用程序
  • “大数据应用场景”之隔壁老王(连载四)
  • 2017前端实习生面试总结
  • 2019.2.20 c++ 知识梳理
  • Fundebug计费标准解释:事件数是如何定义的?
  • Hexo+码云+git快速搭建免费的静态Blog
  • JavaScript/HTML5图表开发工具JavaScript Charts v3.19.6发布【附下载】
  • js中的正则表达式入门
  • leetcode378. Kth Smallest Element in a Sorted Matrix
  • oldjun 检测网站的经验
  • swift基础之_对象 实例方法 对象方法。
  • 发布国内首个无服务器容器服务,运维效率从未如此高效
  • 分享一个自己写的基于canvas的原生js图片爆炸插件
  • 前端技术周刊 2019-02-11 Serverless
  • 深入 Nginx 之配置篇
  • 【运维趟坑回忆录】vpc迁移 - 吃螃蟹之路
  • ​LeetCode解法汇总2696. 删除子串后的字符串最小长度
  • ​一文看懂数据清洗:缺失值、异常值和重复值的处理
  • (Mac上)使用Python进行matplotlib 画图时,中文显示不出来
  • (pojstep1.3.1)1017(构造法模拟)
  • (机器学习的矩阵)(向量、矩阵与多元线性回归)
  • (转)可以带来幸福的一本书
  • .NET Core 网络数据采集 -- 使用AngleSharp做html解析
  • .Net(C#)常用转换byte转uint32、byte转float等
  • .net反混淆脱壳工具de4dot的使用
  • .NET企业级应用架构设计系列之开场白
  • /bin/bash^M: bad interpreter: No such file ordirectory
  • ??在JSP中,java和JavaScript如何交互?
  • [ vulhub漏洞复现篇 ] Apache APISIX 默认密钥漏洞 CVE-2020-13945
  • [ 英语 ] 马斯克抱水槽“入主”推特总部中那句 Let that sink in 到底是什么梗?
  • []C/C++读取串口接收到的数据程序
  • [100天算法】-每个元音包含偶数次的最长子字符串(day 53)
  • [2016.7 day.5] T2
  • [2018-01-08] Python强化周的第一天
  • [④ADRV902x]: Digital Filter Configuration(发射端)
  • [AutoSar]BSW_OS 02 Autosar OS_STACK
  • [AX]AX2012 SSRS报表Drill through action
  • [BROADCASTING]tensor的扩散机制
  • [C#基础]说说lock到底锁谁?
  • [CC2642R1][VSCODE+Embedded IDE+IAR Build+Cortex-Debug] TI CC2642R1基于VsCode的开发环境
  • [CISCN2019 华东北赛区]Web2