跳到主要内容

BM82. 买卖股票的最好时机(三)

题目描述​

给定数组 prices,prices[i] 是某只股票第 i 天的价格。 你最多可以对该股票进行两笔交易(一笔 = 一次买入 + 一次卖出), 再次购买前必须卖出之前的股票。求最大收益;不能获利返回 0。

输入格式​

  • prices:int 型一维数组,表示每一天的股票价格。

输出格式​

返回 int 型,最大收益(不能获利则为 0)。

示例​

示例 1​

输入:

prices = [8,9,3,5,1,3]

输出:

4

说明: 第 3 天买第 4 天卖(+2),第 5 天买第 6 天卖(+2),合计 4。

示例 2​

输入:

prices = [9,8,4,1]

输出:

0

说明: 价格持续下跌,不交易最优。

示例 3​

输入:

prices = [1,2,8,3,8]

输出:

12

说明: 第一笔第 1 天买第 3 天卖(+7),第二笔第 4 天买第 5 天卖(+5),合计 12。


解题思路​

第一步:理解问题本质​

最多两笔交易,且任意时刻最多持有一股。 「最多」意味着可以只做一笔、甚至不交易。难点在于两笔交易是串行的: 第二笔只能在第一笔卖出之后开始。

第二步:状态机建模​

把「手上资产状态」拆成四个阶段,每个阶段维护「该阶段结束后的最大收益」:

状态含义
buy1完成第一次买入后的收益(账面为负)
sell1完成第一次卖出后的收益
buy2完成第二次买入后的收益
sell2完成第二次卖出后的收益

每天用当天的价格 p 依次更新这四个状态:

buy1  = max(buy1,  -p)          # 之前已买入 vs 今天第一次买入
sell1 = max(sell1, buy1 + p) # 之前已卖出 vs 今天第一次卖出
buy2 = max(buy2, sell1 - p) # 之前已买第二次 vs 今天第二次买入
sell2 = max(sell2, buy2 + p) # 之前已卖第二次 vs 今天第二次卖出

四个状态初始化为 -∞,唯一的效果是强制「先买才能卖」。 最终答案是 sell2(也保证至少为 0)。

第三步:为什么「最多两笔」也兼容​

初始 sell2 = -∞,但每天都会用 sell2 = max(sell2, buy2 + p) 更新; 即便只做一笔交易,sell2 也能通过 buy2(取自 sell1)继续传递利润, 所以「只做一笔」「不做」都被覆盖,最终回答不会比真实值小。


完整代码实现​

算法可视化 · 逐帧回放这道题的代码16 帧 · 录制输入 [8,9,3,5,1,3]
from typing import List

NEG = float('-inf')


class Solution:
def maxProfit(self, prices: List[int]) -> int:
"""最多两笔交易:四状态滚动 DP"""
buy1 = sell1 = buy2 = sell2 = NEG
for p in prices:
buy1 = max(buy1, -p) # 第一次买入:账面 -p
sell1 = max(sell1, buy1 + p) # 第一次卖出
buy2 = max(buy2, sell1 - p) # 第二次买入
sell2 = max(sell2, buy2 + p) # 第二次卖出
return max(sell2, 0)

示例推演​

以 prices = [1,2,8,3,8] 为例,四个状态的关键变化:

处理 pbuy1sell1buy2sell2
1-10-10
2-11-11
8-17-17
3-1747
8-17412

最后一天 sell2 达到 12:第一笔赚 7,第二笔用 buy2 = 7 - 3 = 4 再赚 5, 合计 12,与答案一致。


复杂度分析​

解法时间复杂度空间复杂度说明
状态机 DPO(n)O(1)推荐
枚举分界点O(n²)O(1)不推荐

易错点总结​

1. 状态初始化成了 0​

buy1/buy2 若初始化为 0,会表示「不花钱就买入」,答案偏高。 必须用 -∞,让买入必须先付出成本。

2. 更新顺序​

四个状态必须按 buy1 → sell1 → buy2 → sell2 的顺序更新, 因为后面的状态依赖前面刚更新的值。顺序乱了会用到过期状态。

3. 把「最多两笔」当成「必须两笔」​

返回 max(sell2, 0),允许只做一笔或不交易。


扩展思考​

  • 最多 k 笔交易可以把状态扩成 2k 个(buy_1..buy_k、sell_1..sell_k)。
  • 加入手续费或冷冻期时,只需在买卖转移上减去手续费 / 跳过若干天。

相关题目​

自测​

加载评论中...