下面我把LeetCode 3652:按策略买卖股票的最佳时机
完整做一遍:从建模 → 思路 → 算法 → 代码(含详细注释),一步一步来。
原题:
给你两个整数数组 prices 和 strategy,其中:
prices[i] 表示第 i 天某股票的价格。 strategy[i] 表示第 i 天的交易策略,其中: -1 表示买入一单位股票。 0 表示持有股票。 1 表示卖出一单位股票。 同时给你一个 偶数 整数 k,你可以对 strategy 进行 最多一次 修改。一次修改包括: 选择 strategy 中恰好 k 个 连续 元素。 将前 k / 2 个元素设为 0(持有)。 将后 k / 2 个元素设为 1(卖出)。 利润 定义为所有天数中 strategy[i] * prices[i] 的 总和 。 返回你可以获得的 最大 可能利润。注意: 没有预算或股票持有数量的限制,因此所有买入和卖出操作均可行,无需考虑过去的操作 做出这道题,并给出详细解释,分析,和注释
一、题意重述(用“数学 + 业务”语言)
给定:
prices[i]:第i天股价strategy[i]:第i天策略-1:买入 → 对利润贡献-prices[i]0:持有 → 贡献01:卖出 → 贡献+prices[i]
原始利润
[
profit = \sum strategy[i] \times prices[i]
]
你可以做最多一次修改
修改规则:
- 选一个长度为
k的连续子数组 - 前
k/2天 → 全部改成0 - 后
k/2天 → 全部改成1
⚠️k是偶数
目标
修改 0 次或 1 次,使总利润最大
二、关键思维:问题本质是什么?
1️⃣ 原利润是固定的
baseProfit = Σ strategy[i] * prices[i]我们只需要关心:
“一次修改,最多能额外增加多少利润”
2️⃣ 修改 = 对一段区间的“利润差值”
设修改区间是[l, r],长度k
其中:
[l, l + k/2 - 1]→ 改为0[l + k/2, r]→ 改为1
原贡献
Σ strategy[i] * prices[i]新贡献
前半段:0 后半段:+prices[i]增量 = 新 - 原
三、把“增量”拆成两个部分
🔹 前半段(变成 0)
原来:strategy[i] * prices[i] 现在:0 增量:- strategy[i] * prices[i]🔹 后半段(变成卖出)
原来:strategy[i] * prices[i] 现在:+prices[i] 增量:(1 - strategy[i]) * prices[i]✅ 单次修改的总增量
[
\Delta =
\sum_{前半段} (-strategy[i] \cdot prices[i])
+
\sum_{后半段} ((1 - strategy[i]) \cdot prices[i])
]
四、算法思路(滑动窗口)
为什么用滑动窗口?
- 区间长度固定为
k - 要枚举所有连续长度为
k的区间 - 每次移动只加减一个元素
👉O(n)
核心变量
baseProfit:不修改的利润delta:当前窗口的利润增量maxDelta:所有窗口中最大的增量
滑动时怎么更新?
设当前窗口[i - k + 1, i]
新进入的元素i
- 若
i在后半段 → 加(1 - strategy[i]) * prices[i]
移出的元素i - k
- 若它原来在前半段 → 减
-strategy[x] * prices[x] - 若在后半段 → 减
(1 - strategy[x]) * prices[x]
五、完整 Java 实现(带详细注释)
classSolution{publiclongmaxProfit(int[]prices,int[]strategy,intk){intn=prices.length;// 1. 计算原始利润longbaseProfit=0;for(inti=0;i<n;i++){baseProfit+=(long)strategy[i]*prices[i];}// 如果 k 为 0 或无法修改if(k==0||k>n){returnbaseProfit;}inthalf=k/2;longdelta=0;longmaxDelta=0;// 2. 初始化第一个窗口 [0, k-1]for(inti=0;i<k;i++){if(i<half){// 前半段 → 变成 0delta+=-(long)strategy[i]*prices[i];}else{// 后半段 → 变成卖出delta+=(long)(1-strategy[i])*prices[i];}}maxDelta=Math.max(0,delta);// 3. 滑动窗口for(inti=k;i<n;i++){intout=i-k;// 移除 outif(out<out+half){delta-=-(long)strategy[out]*prices[out];}else{delta-=(long)(1-strategy[out])*prices[out];}// 加入 iif(i<out+k-half){delta+=-(long)strategy[i]*prices[i];}else{delta+=(long)(1-strategy[i])*prices[i];}maxDelta=Math.max(maxDelta,delta);}// 4. 原始利润 + 最佳增量returnbaseProfit+maxDelta;}}六、复杂度分析
| 项目 | 复杂度 |
|---|---|
| 时间 | O(n) |
| 空间 | O(1) |
七、为什么这题是「中等」但难度偏高?
题目描述是业务语言
真正考的是:
- 数学建模能力
- 把“策略变化”转为“区间增量”
很多人卡在:
- 不知道“利润增量”怎么计算
- 想 DP,其实不需要