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

A.每日一题——3562. 折扣价交易股票的最大利润

题目链接:3562. 折扣价交易股票的最大利润(困难)

算法原理:

解法:01背包+动态规划

297ms击败34.61%

时间复杂度O(N∗Budget)

①树形结构构建:将层级关系(hierarchy)转换为邻接表形式的树形结构,节点从 1-based 转为 0-based 索引
②后序 DFS 遍历子树:对每个节点 x,递归处理其所有子节点,获取子节点子树的状态数组(记录不同预算 j、父节点状态 k 下的最大利润)
③子树状态合并(01 背包):采用 01 背包逆序遍历预算的方式,将所有子节点的状态数组合并为当前节点的子树合并状态(subF),表示预算 j、当前节点状态 k 下的子树总利润
④当前节点状态计算:根据父节点状态 k(0/1)计算当前节点的购买成本,分预算足够 / 不足两种情况,取 “不买当前节点” 和 “买当前节点(利润为未来价 - 成本)” 的最大值,生成当前节点的最终状态数组
⑤根节点结果提取:调用 DFS 处理根节点(索引 0),返回预算 budget、根节点无父节点(状态 0)时的最大利润作为答案
核心要点:
用后序 DFS处理树形结构,保证先处理子节点再处理父节点
用01 背包逆序遍历合并多个子树的状态,解决预算分配的优化问题
父节点状态影响当前节点的购买成本,通过状态数组记录这一依赖关系

答疑

Q1:为什么上面枚举了 subF 这个数组之后,下面又要枚举这个 f 的数组?这为什么枚举两遍?它俩有啥区别吗?

枚举subF:合并子树的背包状态

枚举f:结合父节点状态推导返回值

Java代码:

class Solution { public int maxProfit(int n, int[] present, int[] future, int[][] hierarchy, int budget) { //构建树形邻接表 List<Integer>[] g=new ArrayList[n];//开了大小为n的长度 Arrays.setAll(g,i->new ArrayList<>()); //员工1对应索引0,因为恰好n的大小的空间 for(int[] e:hierarchy) g[e[0]-1].add(e[1]-1); //从根节点开始dfs,根节点无父节点,状态为未购买(0) //f[j][0]:根节点预算j下的最大利润 int[][] f0=dfs(0,g,present,future,budget); return f0[budget][0]; } //x:当前处理节点,g:树形邻接表,present:当前股票价格数组,future:股票未来价格数组,budget:总预算 private int[][] dfs(int x,List<Integer>[] g,int[] present,int[] future,int budget){ //计算从x的所有儿子子树y中,能得到的最大利润之和(x不买,x买) //subF[j][k]:合并x的所有子树后,预算j下,x自身状态为k时的最大利润 //初始化为0:没有子树时利润为0 int[][] subF=new int[budget+1][2]; //遍历x的每个直接子节点y,合并子树y的状态到subF for(int y:g[x]){ //递归处理子节点y,得到y子树的状态数组fy int[][] fy=dfs(y,g,present,future,budget); //01背包的逆序遍历:避免重复选择,从大预算到小预算更新 for(int j=budget;j>=0;j--){ //枚举子树y的预算为jy //当作一个体积为jy,价值为fy[jy][k]的物品 //把总预算j拆分成给子树y的运算jy和留给当前节点的剩余预算j-jy来合并子树状态 for(int jy=0;jy<=j;jy++) for(int k=0;k<2;k++) //状态转移:总预算j=剩余j-jy+给y的jy //剩余预算j-jy的利润(subF[j-jy][k])+y子树预算jy的利润(fy[jy][k]) subF[j][k]=Math.max(subF[j][k],subF[j-jy][k]+fy[jy][k]); } } //f[j][k]:最终返回的状态数组,k表示x的父节点状态 //计算从子树x中,能得到的最大利润之和(x父节点不买,x父节点买) int[][] f=new int[budget+1][2]; for(int j=0;j<=budget;j++){ for(int k=0;k<2;k++){ //k=0表示x父节点不买,k=1表示x父节点买 int cost=present[x]/(k+1); if(j>=cost) //不买x,转移源是subF[j][0] //买x,转移源是subF[j-cost][1],因为对于子树来说,父节点一定买 f[j][k]=Math.max(subF[j][0],subF[j-cost][1]+future[x]-cost); else //只能不买x f[j][k]=subF[j][0]; } } return f; } }
http://www.cnnetsun.cn/news/94718.html

相关文章:

  • 圣默思 Teledyne DalsaFilr SWIR相机
  • Go 语言结构
  • JavaScript for 循环详解
  • 5步搞定SillyTavern版本升级:告别烦恼的完整指南
  • 猫头虎AI开源分享:如何批量获取稀土掘金社区文章阅读量暨文章阅读量数据批量提取解决方案
  • DBO-RBF多变量回归预测 优化宽度+中心值+连接权值 (多输入单输出)Matlab代码
  • 亲测!WordPress网站接入聚合登录实践
  • 15、Mozilla模板系统:功能、构建与应用实践
  • Ofd2Pdf完整使用教程:5分钟掌握OFD转PDF的终极技巧
  • 毕业论文操作全流程:以营销类选题为例
  • 20、Mozilla 开发中的脚本、数据结构与数据库支持
  • 小学生学C++编程 (一维数组精讲)
  • 研发绩效评估的关键指标
  • [CISCN2019 华北赛区 Day1 Web2]ikun
  • LobeChat投诉处理建议生成引擎
  • 杨建允:AI搜索优化赋能全链路营销的全流程
  • AI原生应用中的长尾用户意图理解解决方案
  • 23、Vim 多文件查找替换与全局命令使用技巧
  • 如何避免MySQL死锁?资深DBA的9条黄金法则
  • arcpy导出excel表
  • 视频硬字幕AI去除终极方案:本地化无损修复技术详解
  • BetterNCM插件完整教程:从零开始打造你的专属音乐工作站
  • 大模型注意力机制全解析:从MHA到MoBA,一文掌握七种核心算法
  • LobeChat能否实现AI调酒师?饮品配方创意与口味偏好匹配
  • 如何快速绕过iOS激活锁:AppleRa1n完整解决方案指南
  • 3分钟深入解析LLM注意力机制:轻松掌握核心原理!
  • UnrealPakViewer终极指南:Pak文件分析与虚幻引擎资源管理完整教程
  • TradingView图表库K线生成机制深度解析与实战指南
  • 智能字体协作者:AutoCAD字体自动修复的终极解决方案
  • [深度复盘] 恋爱是一场分布式系统灾难?手把手教你用状态机(FSM)重构女神的“潜台词”逻辑