news 2026/4/23 17:20:35

LeetCode 每日一题笔记 日期:2025.12.17 题目:3573.买卖股票的最佳时机Ⅴ

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
LeetCode 每日一题笔记 日期:2025.12.17 题目:3573.买卖股票的最佳时机Ⅴ

LeetCode 每日一题笔记

0. 前言

  • 日期:2025.12.17
  • 题目:3573.买卖股票的最佳时机Ⅴ
  • 难度:中等
  • 标签:动态规划

1. 题目理解

问题描述
给定整数数组prices表示股票每日价格,整数k表示最多可完成的交易次数(一次“做多”或“做空”平仓算一笔交易)。交易规则支持两种操作:

  1. 做多:先买入股票,后卖出平仓(利润=卖出价-买入价);
  2. 做空:先卖出股票(卖空),后买回平仓(利润=卖出价-买回价)。
    要求在最多完成k笔交易的前提下,返回能获得的最大利润,未进行任何交易时利润为 0。

示例

示例 1:
输入:prices = [3,2,6,5,0,3], k = 2
输出:7
解释:

  • 第1天做多买入(价格2),第3天卖出平仓(价格5),利润3(完成1笔交易);
  • 第5天做空卖出(价格0),第6天买回平仓(价格3),利润-3(放弃该操作);
  • 最优方案:第1天做多买入(2),第3天卖出(6)利润4;第5天做多买入(0),第6天卖出(3)利润3;总利润7(2笔交易)。

示例 2:
输入:prices = [1,2,3,4,5], k = 1
输出:4
解释:做多:第1天买入(1),第5天卖出(5),利润4(1笔交易)。

示例 3:
输入:prices = [7,6,4,3,1], k = 2
输出:0
解释:无论做多/做空均无利润,最优选择不交易。

2. 解题思路

核心观察

  1. 状态维度:每日交易状态可拆分为「天数」「已完成交易次数」「持仓状态」三维:
    • 持仓状态:0=无持仓(平仓/未操作)、1=做多持仓(买入未卖)、2=做空持仓(卖空未买回);
  2. 交易规则
    • 做多平仓(1→0)或做空平仓(2→0)算完成1笔交易,交易次数+1;
    • 开仓(0→1/0→2)不消耗交易次数,仅平仓消耗;
  3. 最优子结构:第i天的最大利润仅依赖第i-1天的状态,符合动态规划特征。

算法步骤

  1. 初始化DP数组:定义三维数组dp[i][j][s]表示第i天、完成j笔交易、状态s时的最大利润,初始值设为极小值(表示不可达),仅第0天基础状态初始化;
  2. 状态转移
    • 无持仓(0):来自前一天无持仓、前一天做多平仓、前一天做空平仓;
    • 做多持仓(1):来自前一天做多持仓、前一天无持仓开多仓;
    • 做空持仓(2):来自前一天做空持仓、前一天无持仓开空仓;
  3. 结果计算:最后一天所有交易次数下,无持仓状态的最大利润(落袋为安,持仓无利润)。

3. 代码实现

publicstaticlongmaximumProfit(int[]prices,intk){intn=prices.length;// 三维DP数组:dp[i][j][s]// i:第i天;j:已完成j笔交易;s:0=无持仓,1=做多持仓,2=做空持仓long[][][]dp=newlong[n][k+1][3];// 初始化所有状态为极小值(不可达),避免溢出用Long.MIN_VALUE/2for(inti=0;i<n;i++){for(intj=0;j<=k;j++){dp[i][j][0]=Long.MIN_VALUE/2;dp[i][j][1]=Long.MIN_VALUE/2;dp[i][j][2]=Long.MIN_VALUE/2;}}// 第0天初始状态dp[0][0][0]=0;// 无交易、无持仓,利润0dp[0][0][1]=-prices[0];// 无交易、做多开仓,利润=-股价dp[0][0][2]=prices[0];// 无交易、做空开仓,利润=+股价// 遍历每一天处理状态转移for(inti=1;i<n;i++){for(intj=0;j<=k;j++){// 状态0:无持仓dp[i][j][0]=Math.max(dp[i][j][0],dp[i-1][j][0]);// 前一天无持仓if(j>=1){// 前一天做多持仓,今日平仓(交易次数+1)dp[i][j][0]=Math.max(dp[i][j][0],dp[i-1][j-1][1]+prices[i]);// 前一天做空持仓,今日平仓(交易次数+1)dp[i][j][0]=Math.max(dp[i][j][0],dp[i-1][j-1][2]-prices[i]);}// 状态1:做多持仓dp[i][j][1]=Math.max(dp[i][j][1],dp[i-1][j][1]);// 前一天做多持仓dp[i][j][1]=Math.max(dp[i][j][1],dp[i-1][j][0]-prices[i]);// 今日开多仓// 状态2:做空持仓dp[i][j][2]=Math.max(dp[i][j][2],dp[i-1][j][2]);// 前一天做空持仓dp[i][j][2]=Math.max(dp[i][j][2],dp[i-1][j][0]+prices[i]);// 今日开空仓}}// 最后一天所有交易次数下,无持仓的最大利润longmaxProfit=0;for(intj=0;j<=k;j++){maxProfit=Math.max(maxProfit,dp[n-1][j][0]);}returnmaxProfit;}

4. 代码优化说明

官方题解优化点

  1. 空间优化:将三维DP压缩为二维f[j][s](仅保留交易次数和状态),利用“逆序遍历交易次数”避免状态覆盖,空间复杂度从 O(nk3) 降至 O(k*3);
  2. 状态合并:简化状态转移逻辑,将每日价格遍历与交易次数逆序遍历结合,减少冗余计算;
  3. 边界调整:通过k+2长度的数组规避交易次数边界判断,代码更简洁。

官方题解代码注释

classSolution{publiclongmaximumProfit(int[]prices,intk){// 二维数组:f[j][s] 表示完成j-1笔交易、状态s时的最大利润(空间压缩)long[][]f=newlong[k+2][3];// 初始化不可达状态(防止溢出)for(intj=1;j<=k+1;j++){f[j][1]=Long.MIN_VALUE/2;}f[0][0]=Long.MIN_VALUE/2;// 遍历每日价格,逆序处理交易次数(避免覆盖)for(intp:prices){for(intj=k+1;j>0;j--){// 状态0:无持仓,来自做多平仓/做空平仓/无持仓f[j][0]=Math.max(f[j][0],Math.max(f[j][1]+p,f[j][2]-p));// 状态1:做多持仓,来自前序无持仓开仓f[j][1]=Math.max(f[j][1],f[j-1][0]-p);// 状态2:做空持仓,来自前序无持仓开仓f[j][2]=Math.max(f[j][2],f[j-1][0]+p);}}// 最终取完成k笔交易后无持仓的最大利润returnf[k+1][0];}}

5. 复杂度分析

原代码复杂度

  • 时间复杂度:O(n*k)。需遍历n天,每天遍历k+1次交易次数,每次处理3种状态,均为常数级操作;
  • 空间复杂度:O(n*k)。三维DP数组大小为n*(k+1)*3,主导空间开销。

官方题解复杂度

  • 时间复杂度:O(n*k)。遍历n天,每天逆序遍历k+1次交易次数,时间效率与原代码一致;
  • 空间复杂度:O(k)。二维数组大小为(k+2)*3,空间复杂度从线性级降至常数级(相对于n)。

6. 总结

题目核心

本题是“带做空机制的有限次数股票交易”问题,核心是拆分持仓状态+动态规划状态转移,关键在于:

  1. 明确“平仓算交易次数,开仓不算”的规则;
  2. 区分做多/做空两种持仓状态的转移逻辑;
  3. 最终结果仅考虑无持仓状态(持仓未平仓无实际利润)。

关键知识点

  1. DP状态压缩:利用“当天状态仅依赖前一天”的特性,将三维DP压缩为二维,大幅降低空间开销;
  2. 状态初始化:用极小值标记不可达状态,避免溢出需将初始值设为Long.MIN_VALUE/2
  3. 逆序遍历:官方题解中逆序处理交易次数,是01背包思想的延伸,防止同一交易次数被重复更新。

刷题启示

  1. 复杂状态的DP问题,先拆分清晰状态维度(如本题的“天数、交易次数、持仓状态”),再逐一推导转移逻辑;
  2. 空间优化优先考虑“状态压缩”,重点观察状态依赖关系(仅依赖前一阶段则可压缩);
  3. 涉及大数运算时,需注意溢出问题(如用Long存储利润,初始值规避MIN_VALUE直接运算)。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/19 22:31:08

TLS网络安全协议巩固知识基础题(3)

1. TLS 中的 Extended Master Secret 扩展主要解决什么安全问题? A. 防止主密钥被窃取 B. 防止主密钥派生过程中的截断攻击 C. 提高加密算法强度 D. 加快密钥生成速度 答案:B 解析: Extended Master Secret 扩展通过在主密钥派生过程中包含完整的握手消息哈希,防止截断攻…

作者头像 李华
网站建设 2026/4/23 11:29:12

CGAL-6.1 Windows 配置到VS全部项目

CGAL-6.1 Windows 配置到VS全部项目 CGAL可以使用vcpkg安装&#xff0c;不过如果网络不好&#xff0c;可能很多源码下不下来&#xff0c;手动编译步骤也不多 下载链接 官方仓库打包好的cgal-library-6.1 编译好的gmp 编译好的boost-1.90 VS属性表编辑器-VSATEditor 配置 1.在任…

作者头像 李华
网站建设 2026/4/23 15:53:22

通用 AI · Universal AI 2

DAY 4对第一个Universal App 的理解和规划名字&#xff1a;MomentTasker核心功能1.打印/记录功能简单日记记录&#xff08;类似微博&#xff09;照片/音频瞬间捕捉时间地点自动标记每日生成明日的TO DO LIST&#xff08;包含时间、地点&#xff09;&#xff0c;到时间提醒2.简单…

作者头像 李华
网站建设 2026/4/23 11:33:17

计算机毕业设计springboot少儿美术培训机构教培管理系统 基于SpringBoot的少儿美术教培机构综合管理平台 SpringBoot驱动的儿童美术培训中心教务运营系统

计算机毕业设计springboot少儿美术培训机构教培管理系统93gv08oa &#xff08;配套有源码 程序 mysql数据库 论文&#xff09; 本套源码可以在文本联xi,先看具体系统功能演示视频领取&#xff0c;可分享源码参考。当“双减”把学科培训推向边缘&#xff0c;艺术教育反而成为家长…

作者头像 李华
网站建设 2026/4/21 7:45:12

FlutterOpenHarmony动画效果实现指南

前言 动画效果是提升应用用户体验的重要手段&#xff0c;它可以让界面交互更加流畅自然&#xff0c;引导用户注意力&#xff0c;提供操作反馈。在笔记应用中&#xff0c;页面切换、列表项展开、按钮点击等场景都可以通过动画来增强视觉效果。本文将详细介绍如何在Flutter和Ope…

作者头像 李华
网站建设 2026/4/23 13:16:08

关于 iphone抓包软件,我是在什么时候真正意识到选好工具很重要

很长一段时间里&#xff0c;我对 iphone 抓包软件的理解都停留在“能看到请求就够了”。 只要能把接口跑通、参数对得上&#xff0c;抓包这件事本身并不会引起太多关注。 直到有一次线上问题排查&#xff0c;把我从这种想法里拽了出来。 一个看起来和抓包关系不大的问题 问题发…

作者头像 李华