122. 买卖股票 II

中等 含交互动画

学完这道你应该能: 说清它为什么用「贪心」,而不是死记步骤; 合上页面,自己默写出核心代码; 用 30 秒把思路讲清楚。

AI 私教 · 就着本题动画讲
卡住了不用硬扛,按 8 步把这题真正走通。
从读题、试解、找法到手写代码,边问边打勾,适合第一次系统学算法的同学。

题目描述

可以多次买入卖出(手里最多只持一股),求能拿到的最大总利润

prices = [7, 1, 5, 3, 6, 4]
输出 = 7

思路解析

最直接的念头是「找一个谷底买进、找一个峰顶卖出」。但能交易很多次,到底切成几段、每段谷峰在哪,枚举起来又乱又慢,而且根本没必要知道具体的买卖点。

换个角度:把利润拆到每一天。今天比昨天涨,就把这点差价收进口袋(相当于昨天买、今天卖);今天比昨天跌,就空仓什么都不做(加 0)。为什么成立:一段连续上涨 1→5 的总收益 4,正好等于它每天小涨之和;所以「把所有正的日差累加」和「整段买卖」收益完全相等,而且不限次数让我们可以自由分段——逐日贪心就是全局最优。

准备 · 从第 2 天开始:利润 profit 从 0 起。第 1 天(价 7)没有前一天可比,cur 先停在这里,真正的累加从第 2 天开始。

第 2 天 · 7 → 1 算差:走到第 2 天(价 1),先算今天减昨天:1 − 7 = −6,是负的。

第 2 天 · 跌 → 加 0:日差是负的,这天不操作(空仓),profit 加 0、保持 0。这就是负例:下跌日一律跳过,灰掉表示没吃进。

第 3 天 · 1 → 5 算差:走到第 3 天(价 5),算差:5 − 1 = +4,第一次出现正的涨幅。

第 3 天 · 涨 → 吃下:日差为正,把这 4 块吃进口袋:profit 累计到 4。绿色标出的 1 和 5 就是这一段「昨天买、今天卖」赚到的钱。

第 4 天 · 5 → 3 算差:走到第 4 天(价 3),算差:3 − 5 = −2,又是负的。

第 4 天 · 跌 → 加 0:下跌日再次跳过,profit 不动,仍是 4。注意这里没有去「找谷底找峰顶」——只看相邻两天的正负就够了。

第 5 天 · 3 → 6 算差:走到第 5 天(价 6),算差:6 − 3 = +3,又一段上涨。

第 5 天 · 涨 → 吃下:正差再吃下 3 块:profit 从 4 累到 7。绿色的 3 和 6 是这第二段赚到的钱。

第 6 天 · 6 → 4 收尾:最后一天 6 → 4 又是跌,跳过。全程只把两段正涨幅累加:4 + 3 = 7,就是答案。

一段连续上涨(如 1→5)拆成每天的差,求和不变;下跌日加 0 不亏。所以「每个正的日差都拿」就等于全局最优——这就是贪心在这题成立的根本原因。

参考代码(Python)

Python
1def maxProfit(self, prices):
2    profit = 0
3    for i in range(1, len(prices)):           # 从第 2 天起逐天比
4        if prices[i] > prices[i - 1]:         # 今天比昨天涨
5            profit += prices[i] - prices[i - 1]  # 吃下这段涨幅
6    return profit

复杂度分析

  • 时间复杂度:O(n) —— 只从第 2 天到最后扫一遍,每天做一次比较
  • 空间复杂度:O(1) —— 只用 profit 一个变量,不开任何数组

套路模板

记住骨架:相邻两步算增量、只累加正的。前提是「次数不限、各段收益互不影响」——否则(如只能交易一次)不能这么贪。

Python
1# 「操作次数不限、收益可分段独立」的贪心都套
2total = 0
3for i in range(1, n):
4    gain = 收益(i - 1, i)
5    if gain > 0: total += gain            # 只累加正收益
6return total

易错点

  • 错误写法:费劲去找全局最低点买、最高点卖正确写法:只累加每段正的日差 max(0, 今−昨)(不限次数时根本不用知道具体谷峰,分段累加正涨幅就是最优,找谷峰反而又慢又容易切错段)
  • 错误写法:把这套累加直接用在「只能交易一次」的 LC121正确写法:一次交易要维护历史最低价 minPrice 求最大单段差(次数受限时利润不可分段独立累加,简单加正差会偏大)
  • 错误写法:for i in range(len(prices)) 从 0 开始正确写法:for i in range(1, len(prices))(第 1 天没有「昨天」,从 0 起会越界访问 prices[-1])

以上文字与上方动画完全同一思路:先看动画建立直觉 → 读文字巩固 → 关掉页面自己默写一遍代码,能写出来才算真的掌握

下一题 →63. 不同路径 II ← 返回题库