BM81 买卖股票的最好时机(二)¶
中等通过率 62.53%python3核心代码模式样例通过牛客 AC贪心动态规划
讲解章节:线性 DP
一句话
不限交易次数,把每一段上涨都吃掉:相邻差为正就累加。
解题思路¶
这题考什么¶
交易次数不限、且卖出当天可以立刻再买入,这两条合起来让收益可以任意拆分:
也就是说,任何一段「低买高卖」的收益都等于它跨过的相邻日差值之和。 既然拆分自由,最优策略就是把所有为正的相邻差值全部收进来、把负的全部跳过 (那两天不持仓)。这就是贪心解:
对应的 DP 视角是两个状态:
转移方程:
初值 hold[0] = -prices[0]、empty[0] = 0,答案 empty[n-1]。 与 BM80 的唯一差别是买入那一步从 empty[i-1] 起算而不是从 0 起算—— 「交易次数」这一维在这里被彻底放开,于是不必记录已经做了几笔。 可以证明它与上面的贪心累加恒等;贪心写法只用一个累加器,常数最小。
数据规模与复杂度¶
1 <= n <= 1e5(备注给到 2e5),1 <= prices[i] <= 1e4,时限 2 秒(其他语言)。 单趟扫描,时间 O(n)、空间 O(1),达到题面进阶要求。 收益上界不超过 2e5 * 1e4 = 2e9,Python 整数不受字长限制。
坑在哪¶
- 「当天卖出可以当天再买入」是拆分成立的前提。若题目改成卖出后要冷冻一天, 相邻差值就不能自由拼接,贪心立刻失效,必须回到带状态的 DP。
- 这不是 BM80 那道题:不能只找一次最大差值。[1,2,1,2] 的答案是 2 而不是 1。
- 反过来也不能把这里的贪心搬去 BM80——那里只允许一笔交易。 三道股票题的差别全在「交易次数」这一维上,转移式的其余部分是一样的。
- 相邻差为 0 时加不加都一样,判 d > 0 少做一次无谓的累加。
- 循环从下标 1 起步;n 为 0 或 1 时循环体一次都不进,返回 0。
样例复核¶
[8,9,2,5,4,7,1]:正的相邻差是 +1(8->9)、+3(2->5)、+3(4->7), 合计 7,与期望输出一致。
参考实现¶
| solutions/nowcoder/BM81/sol.py | |
|---|---|
[:octicons-arrow-left-16: BM80](BM80.md) [BM82 :octicons-arrow-right-16:](BM82.md)