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

《LeetCode 714 买股票的最佳时机含手续费 || LeetCode 123 买卖股票的最佳时机|||》

一、题目

二、做题思路

2.1 状态表示(核心基础)

本题要求计算在无限次交易且每笔交易扣除手续费条件下的最大利润。由于每天结束时存在两种状态——持有股票不持有股票,我们定义两个状态数组:

  • f[i]表示第i天结束后,持有股票(即当天持有股票)的最大利润

  • g[i]表示第i天结束后,不持有股票(即当天空仓)的最大利润

2.2 状态转移方程(关键难点)

每天可以进行买入、卖出或观望操作,两种状态之间的转移关系如下:

  • 持有股票f[i]:可从两种情况转移——(1)前一天就持有f[i-1](继续持有);(2)今天买入,必须从前一天空仓g[i-1]转移,并减去今日股价prices[i]。因此f[i] = max(f[i-1], g[i-1] - prices[i])

  • 不持有股票g[i]:可从两种情况转移——(1)前一天就空仓g[i-1](继续空仓);(2)今天卖出,必须从前一天持有f[i-1]转移,加上今日股价并扣除手续费fee。因此g[i] = max(g[i-1], f[i-1] + prices[i] - fee)

2.3 初始化(边界防护)

第 0 天(第一天)的初始状态:

  • f[0] = -prices[0](买入股票,利润为负股价)。

  • g[0] = 0(空仓,无交易,利润为 0)。
    prices为空,直接返回 0,避免越界。

2.4 填表顺序(递推方向)

每个i状态仅依赖i-1的状态,因此必须从左到右(即i从 1 到n-1)依次填充两个数组,确保每个状态计算时,其所有前置状态均已就绪

2.5 返回值(目标映射)

题目要求返回最大利润。最后一天(下标n-1不持有股票的利润通常大于等于持有股票的利润(因为持有股票可随时卖出获利),但为严谨,取两者较大值。因此返回max(f[n-1], g[n-1])

三、代码

class Solution { public: int maxProfit(vector<int>& prices, int fee) { int n = prices.size(); // 边界处理:若无交易日,利润为0 if (n == 0) return 0; // 1. 创建dp表(两个一维数组) // f[i] : 第 i 天结束后,持有股票(即当天持有股票)的最大利润 // g[i] : 第 i 天结束后,不持有股票(即当天空仓)的最大利润 vector<int> f(n); vector<int> g(n); // 2. 初始化(第 0 天) f[0] = -prices[0]; // 第 0 天买入,利润为负的股价 g[0] = 0; // 第 0 天空仓,利润为0 // 3. 填表顺序:从左到右(i 从 1 到 n-1) for (int i = 1; i < n; i++) { // 4. 状态转移方程: // 持有股票:要么前一天就持有(f[i-1]),要么今天买入(从空仓 g[i-1] 转入,减去今日价格) f[i] = max(f[i - 1], g[i - 1] - prices[i]); // 不持有股票:要么前一天就空仓(g[i-1]),要么今天卖出(从持有 f[i-1] 转入,加今日价格并扣除手续费) g[i] = max(g[i - 1], f[i - 1] + prices[i] - fee); } // 5. 返回值:最后一天两种状态的最大利润(卖出后空仓大概率更优,但取两者较大值更严谨) return max(f[n - 1], g[n - 1]); } };

四、流程图

五、题目

六、做题思路

6.1 状态表示(核心基础)

本题要求计算在最多完成两笔交易条件下的最大利润。由于交易次数有限(0、1、2),我们需要同时记录持仓状态已完成交易次数。因此定义两个二维数组:

  • f[i][j]表示第i天结束后,持有股票,并且已经完成了j次交易(即卖出过j次)的最大利润

  • g[i][j]表示第i天结束后,不持有股票,并且已经完成了j次交易的最大利润
    其中j的取值为 0、1、2,分别对应未完成交易、完成一笔、完成两笔。

6.2 状态转移方程(关键难点)

每天可以选择买入、卖出或观望,且交易次数在卖出时增加(买入不增加次数)。转移关系如下:

  • 持有股票f[i][j]:可从两种情况转移——(1)前一天就持有f[i-1][j](继续持有);(2)今天买入,必须从前一天不持有且同交易次数j的状态g[i-1][j]转移,并减去今日股价。因此f[i][j] = max(f[i-1][j], g[i-1][j] - prices[i])

  • 不持有股票g[i][j]:可从两种情况转移——(1)前一天就不持有g[i-1][j](继续空仓);(2)今天卖出,必须从前一天持有且交易次数为j-1的状态f[i-1][j-1]转移(卖出增加一次交易),并加上今日股价。注意j至少为 1 时才能卖出。因此g[i][j] = max(g[i-1][j], (j>=1 ? f[i-1][j-1] + prices[i] : -INF))

6.3 初始化(边界防护)

所有状态初始化为负无穷-INF),表示不可达。第 0 天(第一天)的合理状态为:

  • f[0][0] = -prices[0](买入第一天的股票,持有且交易 0 次)。

  • g[0][0] = 0(不持有且交易 0 次,未进行任何操作)。
    其余状态(如f[0][1]g[0][2]等)保持负无穷,因为第一天不可能完成交易。

6.4 填表顺序(递推方向)

每个i状态仅依赖i-1的状态,且同一i内不同j之间无依赖关系,因此必须按时间从左到右(即i从 1 到n-1)遍历,内部j从 0 到 2 顺序任意。确保每个状态计算时,其所有前置状态均已就绪

6.5 返回值(目标映射)

题目要求返回最大利润。最后一天(下标n-1)不持有股票的利润一定优于持有状态(因为持有股票可卖出获利),所以只需考虑g[n-1][0]g[n-1][1]g[n-1][2]中的最大值。因此返回max(g[n-1][0], g[n-1][1], g[n-1][2])

七、代码

class Solution { public: int maxProfit(vector<int>& prices) { const int INF = 0x3f3f3f3f; // 定义一个足够大的正数,用于表示负无穷 int n = prices.size(); if (n == 0) return 0; // 边界处理:无交易日 // 1. 创建dp表(两个二维数组) // f[i][j] : 第 i 天结束后,持有股票,并且已经进行了 j 次交易(卖出次数)的最大利润 // g[i][j] : 第 i 天结束后,不持有股票,并且已经进行了 j 次交易(卖出次数)的最大利润 // 其中 j 的取值范围为 0,1,2(最多两笔交易) vector<vector<int>> f(n, vector<int>(3, -INF)); // 初始化为负无穷,表示不可达状态 auto g = f; // 同样初始化 // 2. 初始化(第 0 天) // 持有股票,已交易0次:买入第一天的股票,利润为 -prices[0] f[0][0] = -prices[0]; // 不持有股票,已交易0次:未进行任何操作,利润为 0 g[0][0] = 0; // 其他状态(如 f[0][1], f[0][2] 等)保持负无穷,表示第一天不可能已经完成交易 // 3. 填表顺序:时间从前往后(i 从 1 到 n-1),交易次数 j 从 0 到 2(但内部转移无顺序依赖) for (int i = 1; i < n; i++) { for (int j = 0; j < 3; j++) { // 4. 状态转移方程: // 持有股票状态: // - 前一天就持有:f[i-1][j] // - 今天买入:需要从前一天不持有且同次数 j 的状态转移,减去今日价格 f[i][j] = max(f[i - 1][j], g[i - 1][j] - prices[i]); // 不持有股票状态: // - 前一天就不持有:g[i-1][j](继承) g[i][j] = g[i - 1][j]; // - 今天卖出:必须从持有状态且交易次数为 j-1 转移(卖出增加一次交易),加上今日价格 if (j >= 1) { g[i][j] = max(g[i][j], f[i - 1][j - 1] + prices[i]); } // 注:若 j=0,则无法从卖出转移(因为还未进行过交易),保持继承状态 } } // 5. 返回值:最后一天不持有股票且交易次数为 0、1、2 三种情况中的最大值 // 因为最终利润最大时必定不持有股票(持有可视为未实现收益,但卖掉会更优或相等) return max({g[n - 1][0], g[n - 1][1], g[n - 1][2]}); } };

八、流程图

http://www.jsqmd.com/news/1147415/

相关文章:

  • IIM-20670运动传感器与PIC18微控制器的工业应用方案
  • 把ADC精度榨到极限:硬核拆解DABL-G511采集卡的模拟/数字隔离架构与电源拓扑
  • IIM-20670与STM32L162ZE的高精度运动跟踪方案
  • IIM-20670与MK64FN1M0VDC12的高精度运动跟踪方案
  • CRA网络弹性法案解读:欧盟数字产品网络安全合规框架与产品分类
  • 低成本高精度IMU姿态追踪方案设计与实现
  • 如何快速掌握DriverStore Explorer:Windows驱动管理的终极指南
  • Openclaw本地部署实战:从环境搭建到PDF分析全链路打通
  • IIM-20670运动传感器与PIC32MZ微控制器的工业应用方案
  • iOS 26.5越狱终极指南:解锁iPhone隐藏功能的完整教程
  • IIM-20670与PIC18F45K80的高精度运动跟踪方案
  • Display Driver Uninstaller:显卡驱动清理终极指南与问题解决方案
  • 原来知名的多媒体会议音响设备供应商背后有这么多门道?
  • 42、<简单>数字方阵-1
  • IIM-20670与PIC18F4553的6轴运动跟踪系统设计
  • 6款常用接口/保护芯片(SN74HC244/ACS724等)电路设计与PCB布局要点
  • IIM-20670运动传感器与STM32F437ZG的工业级应用方案
  • GetQzonehistory:3分钟学会备份你的QQ空间全部历史记录
  • ZenlessZoneZero-OneDragon:终极免费自动化工具,解放你的绝区零游戏时间
  • 云裳试衣专业吗
  • BMI323与PIC18F25K80组合在运动感知中的应用
  • Atlas 300I duo mindie 部署qwen3-vl-30b-a3b笔记
  • Fiverr新闻稿外链流程 | 筛选靠谱外包的4个排雷指标
  • Parsec VDD实战指南:5个技巧打造高性能Windows虚拟显示器驱动架构
  • 高效虚拟显示驱动实战指南:从游戏串流到多屏工作流的完整解决方案
  • 一键搞定完整网页截图:Chrome全屏截图插件终极指南
  • 【AI学习之旅02】AI全景图:一张图看懂AI生态——机器学习/深度学习/大模型关系与术语扫盲
  • BMI323与MK51DN512CLQ10在运动控制中的高效应用
  • 容器故障检测系统CPDS-analyzer:终极指南,快速诊断容器亚健康状态
  • 【JAVA毕设源码分享】基于 Spring Boot 的旅行指南系统的设计与实现(程序+文档+代码讲解+一条龙定制)