news 2026/5/15 16:09:43

LeetCode 3573. 买卖股票的最佳时机 V - 动态规划解法详解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
LeetCode 3573. 买卖股票的最佳时机 V - 动态规划解法详解

题目描述

给你一个整数数组prices,其中prices[i]是第 i 天股票的价格,以及一个整数k

你最多可以进行k 笔交易,每笔交易可以是以下任一类型:

  1. 普通交易(做多):在第 i 天买入,然后在之后的第 j 天卖出(i < j)。利润 =prices[j] - prices[i]
  2. 做空交易:在第 i 天卖出,然后在之后的第 j 天买回(i < j)。利润 =prices[i] - prices[j]

限制条件:

  • 必须在开始下一笔交易前完成当前交易
  • 不能在同一天进行多次买入或卖出操作

返回可以获得的最大总利润。

示例

示例 1:

输入: prices = [1,7,9,8,2], k = 2 输出: 14 解释: - 普通交易:第 0 天买入(1),第 2 天卖出(9),利润 = 8 - 做空交易:第 3 天卖出(8),第 4 天买回(2),利润 = 6 - 总利润 = 8 + 6 = 14

示例 2:

输入: prices = [12,16,19,19,8,1,19,13,9], k = 3 输出: 36 解释: - 普通交易:买入(12),卖出(19),利润 = 7 - 做空交易:卖出(19),买回(8),利润 = 11 - 普通交易:买入(1),卖出(19),利润 = 18 - 总利润 = 7 + 11 + 18 = 36

解题思路

问题分析

这道题的关键点在于:

  1. 支持两种交易类型:做多和做空
  2. 交易之间不能重叠(必须先结束一笔再开始下一笔)
  3. 需要找到最优的 k 笔交易组合

状态定义

使用三维 DP 数组:dp[i][j][s]

  • i:当前是第 i 天(0 ≤ i < n)
  • j:已完成的交易数(0 ≤ j ≤ k)
  • s:当前状态
    • s = 0:空仓(不持有任何头寸)
    • s = 1:做多持有(已买入,等待卖出)
    • s = 2:做空持有(已卖出,等待买回)

dp[i][j][s]表示:第 i 天、完成 j 笔交易、处于状态 s 时的最大收益

状态转移方程

1. 空仓状态dp[i][j][0]

可以从以下状态转移而来:

  • 保持空仓:dp[i-1][j][0]
  • 做多平仓(卖出):dp[i-1][j][1] + prices[i](完成第 j 笔交易)
  • 做空平仓(买回):dp[i-1][j][2] - prices[i](完成第 j 笔交易)
dp[i][j][0] = max(dp[i-1][j][0], dp[i-1][j][1] + prices[i], dp[i-1][j][2] - prices[i])

注意:平仓操作会完成一笔交易,所以从j状态平仓。

2. 做多持有状态dp[i][j][1]

可以从以下状态转移而来:

  • 继续持有:dp[i-1][j][1]
  • 今天买入:dp[i-1][j-1][0] - prices[i](开始新交易)
dp[i][j][1] = max(dp[i-1][j][1], dp[i-1][j-1][0] - prices[i])

注意:开始新交易时,从j-1的空仓状态转移(因为这笔交易还未完成)。

3. 做空持有状态dp[i][j][2]

可以从以下状态转移而来:

  • 继续持有:dp[i-1][j][2]
  • 今天卖空:dp[i-1][j-1][0] + prices[i](开始新交易)
dp[i][j][2] = max(dp[i-1][j][2], dp[i-1][j-1][0] + prices[i])

初始化

第 0 天的状态:

  • dp[0][0][0] = 0:初始空仓,收益为 0
  • dp[0][j][1] = -prices[0]:第 0 天买入,成本为负
  • dp[0][j][2] = prices[0]:第 0 天卖空,收益为正

对于所有j ∈ [1, k],都初始化持有状态,这样可以简化边界处理。

最终答案

dp[n-1][k][0]:最后一天、完成 k 笔交易、空仓状态的最大收益。

代码实现

funcmaximumProfit(prices[]int,kint)int64{n:=len(prices)dp:=make([][][]int64,n)fori:=rangedp{dp[i]=make([][]int64,k+1)forj:=rangedp[i]{dp[i][j]=make([]int64,3)}}// 初始化第 0 天的状态forj:=1;j<=k;j++{dp[0][j][1]=int64(-prices[0])dp[0][j][2]=int64(prices[0])}fori:=1;i<n;i++{forj:=1;j<=k;j++{dp[i][j][0]=max(dp[i-1][j][0],max(dp[i-1][j][1]+int64(prices[i]),dp[i-1][j][2]-int64(prices[i])))dp[i][j][1]=max(dp[i-1][j][1],dp[i-1][j-1][0]-int64(prices[i]))dp[i][j][2]=max(dp[i-1][j][2],dp[i-1][j-1][0]+int64(prices[i]))}}returndp[n-1][k][0]}funcmax(a,bint64)int64{ifa>b{returna}returnb}

复杂度分析

  • 时间复杂度:O(n × k)

    • 需要遍历 n 天,每天处理 k 个交易数状态
    • 每个状态的转移是 O(1)
  • 空间复杂度:O(n × k)

    • DP 数组大小为 n × (k+1) × 3

空间优化

可以使用滚动数组优化,只保留前一天的状态,将空间复杂度降到 O(k):

funcmaximumProfit(prices[]int,kint)int64{n:=len(prices)prev:=make([][]int64,k+1)curr:=make([][]int64,k+1)forj:=0;j<=k;j++{prev[j]=make([]int64,3)curr[j]=make([]int64,3)}forj:=1;j<=k;j++{prev[j][1]=int64(-prices[0])prev[j][2]=int64(prices[0])}fori:=1;i<n;i++{forj:=1;j<=k;j++{curr[j][0]=max(prev[j][0],max(prev[j][1]+int64(prices[i]),prev[j][2]-int64(prices[i])))curr[j][1]=max(prev[j][1],prev[j-1][0]-int64(prices[i]))curr[j][2]=max(prev[j][2],prev[j-1][0]+int64(prices[i]))}prev,curr=curr,prev}returnprev[k][0]}

关键要点总结

  1. 区分做多和做空:必须用两个不同的状态来表示,因为它们的收益计算方式不同

    • 做多:买入(负收益)→ 卖出(正收益)
    • 做空:卖出(正收益)→ 买回(负收益)
  2. 交易完成时机:从持有状态转到空仓状态时,才算完成一笔交易,交易数 +1

  3. 初始化技巧:对所有 j 都初始化持有状态,避免复杂的边界判断

  4. 状态转移简洁:用嵌套max函数,一行代码表达所有可能的转移

易错点

  1. ❌ 试图用绝对值统一处理做多和做空 → 无法正确追踪状态转移
  2. ❌ 交易数计数错位 → 应该在"平仓"时完成交易,而非"开仓"时
  3. ❌ 初始化不完整 → 导致某些状态无法转移

相关题目

  • LeetCode 121. 买卖股票的最佳时机(k=1,只能做多)
  • LeetCode 122. 买卖股票的最佳时机 II(k=∞)
  • LeetCode 123. 买卖股票的最佳时机 III(k=2,只能做多)
  • LeetCode 188. 买卖股票的最佳时机 IV(通用 k,只能做多)

本题是最通用的版本,同时支持做多和做空,难度更高。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/13 21:39:22

如何在Kotaemon中自定义检索器以匹配业务需求?

如何在 Kotaemon 中自定义检索器以匹配业务需求&#xff1f; 在金融、医疗和法律等行业&#xff0c;智能问答系统早已不再是“能答就行”的玩具。用户期待的是精准、可追溯、符合组织内部规范的答案——比如一位银行信贷员问“最新的房贷审批流程是什么”&#xff0c;他需要的不…

作者头像 李华
网站建设 2026/5/11 23:08:11

DownKyi视频下载工具:B站内容管理的高效解决方案

DownKyi视频下载工具&#xff1a;B站内容管理的高效解决方案 【免费下载链接】downkyi 哔哩下载姬downkyi&#xff0c;哔哩哔哩网站视频下载工具&#xff0c;支持批量下载&#xff0c;支持8K、HDR、杜比视界&#xff0c;提供工具箱&#xff08;音视频提取、去水印等&#xff09…

作者头像 李华
网站建设 2026/5/3 10:49:34

CefFlashBrowser:Flash内容重生的终极解决方案

CefFlashBrowser&#xff1a;Flash内容重生的终极解决方案 【免费下载链接】CefFlashBrowser Flash浏览器 / Flash Browser 项目地址: https://gitcode.com/gh_mirrors/ce/CefFlashBrowser 随着主流浏览器全面淘汰Flash支持&#xff0c;大量珍贵的Flash资源面临无法访问…

作者头像 李华
网站建设 2026/5/9 4:44:43

EPubBuilder:零基础也能轻松上手的电子书制作神器

EPubBuilder&#xff1a;零基础也能轻松上手的电子书制作神器 【免费下载链接】EPubBuilder 一款在线的epub格式书籍编辑器 项目地址: https://gitcode.com/gh_mirrors/ep/EPubBuilder 还在为制作专业EPUB电子书而烦恼吗&#xff1f;EPubBuilder为您提供了一个简单高效的…

作者头像 李华
网站建设 2026/5/14 4:30:14

8051单片机程序——矩阵键盘+led数码管实现密码锁

以下通过8051实现密码锁的简单程序&#xff0c;并无实用价值&#xff0c;重在记录8051单片机编程的一些重要算法。led数码管&#xff1a;8位共阳型数码管&#xff1b;段码锁存器采用74HC245&#xff1a;8051与74HC245、LED的连接电路图如下&#xff1a;位码锁存器采用74HC138&a…

作者头像 李华
网站建设 2026/5/4 0:58:45

EmotiVoice语音合成引擎的并发请求处理能力测试

EmotiVoice语音合成引擎的并发请求处理能力测试 在虚拟偶像直播中&#xff0c;粉丝发送弹幕“太棒了&#xff01;”&#xff0c;系统瞬间生成带有兴奋语调的主播声音回应&#xff1b;在智能客服平台&#xff0c;上百名用户同时发起咨询&#xff0c;每位客户听到的都是专属音色且…

作者头像 李华