题目描述
思路解析动画文字版
最直接是双重循环:枚举每个买入日 i、每个之后的卖出日 j,取 prices[j] − prices[i] 的最大值。一共约 n²/2 对,数据一大就超时。其实卖在第 j 天时,只关心 j 之前的最低买入价,根本不用回头逐个试。
关键招:从左往右扫一遍,维护一个 minP=「今天之前的历史最低价」。今天卖的利润就是 price − minP,一路取最大值。为什么对:卖在今天,最优的买入点一定是之前的最低价;而 minP 边走边更新,天然只看「今天以前」,自动保证买在卖之前。
两个变量就位:只需两个变量:minP 记历史最低价(开局设无穷大)、profit 记最大利润(开局 0)。
第 0 天 · 价 7:第 0 天:历史最低价先记成 7(紫色 l 标最低价位置),还没有可赚的差价,profit 仍 0。
第 1 天 · 价 1 → 只更新最低价:价格 1 比历史最低还低——这天只更新 minP=1、先不卖(此刻卖反而亏)。最低价指针 l 移到这里,profit 保持 0。
第 2 天 · 价 5 → 第一次能赚:今天价 5,用今天卖能赚 5 − minP = 5 − 1 = 4,刷新最大利润为 4。minP 仍是 1。
第 3 天 · 价 3 → 没超过:今天卖只赚 3 − 1 = 2,没超过已有的 4,最大利润不动。
第 4 天 · 价 6 → 刷新最大:核心一步:今天价 6,用历史最低价 1 买、今天卖能赚 6 − 1 = 5!刷新最大利润 5(绿色标出买点和卖点)。
第 5 天 · 价 4 → 没超过:今天卖只赚 4 − 1 = 3,不超过 5,最大利润不变。
结束:走完一遍,最大利润 5。全程只用 minP 和 profit 两个变量,扫一趟搞定。
提醒:这题不是滑动窗口。滑窗要左右两个指针、靠窗口伸缩;这里只有一个游标从左扫到右,外加一个「历史最低价」标量。所谓「历史最值」就是「目前为止见过的最小/最大」,最大子数组和、接雨水都有它的影子。
迁移阶梯:把这题练到能复述后,再去同类题里迁移:先复用「历史最值 + 当前元素算答案」这套状态,再调整 min/max 方向和算答案的公式。点开 AI 助教问问「LC53 怎么套这个骨架」。
边界三连:边界三连:极端输入先过一遍。价格全跌返回 0(靠 profit 初值),单天无法交易,全涨则首买末卖。
几个高频追问,记住答法——尤其最后一问,别被「股票」字样误导成滑动窗口。
参考代码
class Solution: def maxProfit(self, prices): low = 10**9 ans = 0 for price in prices: low = min(low, price) ans = max(ans, price - low) return ans复杂度
- 时间复杂度:O(n),只扫一遍价格数组,每个元素常数次操作
- 空间复杂度:O(1),只用 minP、profit 两个变量
可套用的代码模板
三语言都是同一个挖空骨架:循环里先更新历史最优 extreme,再用 f(当前, extreme) 更新答案 best。本题把 f 填成「当前价 − 历史最低价」,换题只改 f 和 min/max 方向。注:模板里 C++/Java 用 long 只是防溢出的保守写法,本题数据 int 就够(参考代码用的就是 int);换题若答案可能很大再用 long。
# 骨架:扫一遍,维护「历史最优」,再拿它和当前元素算答案best = 0 # 答案(不操作也合法→初值常设 0)extreme = float("inf") # 历史最优(求最小用 inf;求最大用 -inf)for x in arr: extreme = min(extreme, x) # 先更新历史最优 best = max(best, f(x, extreme)) # 再用「当前 + 历史最优」算答案# 本题:f(x, extreme) = x - extreme易错点
面试追问把动画讲成自己的话
追问为什么不是「全局最大 − 全局最小」?
追问能多次交易(LC122)怎么变?
追问这算滑动窗口吗?
这道题到这就讲完了。动画和文字是同一套思路——别光看,关掉页面自己默写一遍。然后顺着主线继续:
无重复字符的最长子串
LeetCode 3 · 中等 · 沿着 滑动窗口 继续往下推进
把这道题真正学会,再走
图解算法年卡 ¥99 /年
- ✓本题每步动画的吴师兄语音讲解(全站陆续覆盖)
- ✓小欧带 8 步通关训练——追问到不看答案也能写对、能 30 秒讲给面试官听
- ✓学习报告,记录每道题的掌握程度
76k+ GitHub Star · 吴师兄开源图解算法,几十万开发者在看的算法讲解
想成体系刷透这类套路?去图解算法专题