739. 每日温度

中等 含交互动画

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

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

题目描述

给每天温度,求每天还要等几天才能遇到更高温(没有就填 0)。

temps = [73, 74, 75, 71, 69, 72, 76, 73]
输出 = [1, 1, 4, 2, 1, 1, 0, 0]

思路解析

对每一天都从它往后一格格扫,直到撞见更高温——最坏每天都扫到末尾,n 天就是 n² 次比较。重复劳动很多:很多天会被反复扫过。

关键招是用一个栈记住「还没等到更暖天」的下标,栈里温度底高顶低。新一天温度若大于栈顶那天,就说明栈顶等到了——弹出并用「今天下标 − 它的下标」算天数差;一直弹到栈顶比今天高,再把今天压栈。为什么能这样:一旦今天比栈顶高,栈顶这天的答案立刻定死,再不用回头看。

i=0 · 73 入栈:第 0 天 73,栈是空的,直接压入下标 0,让它开始「等更暖的一天」。

i=1 · 74 大于 73 → 结算:74 比栈顶那天(73)高,第 0 天等到了:ans[0] = 1 − 0 = 1。弹出 0,再压入今天 1。

i=2 · 75 大于 74 → 结算:75 又比栈顶(74)高,第 1 天等到了:ans[1] = 2 − 1 = 1。弹出 1,压入今天 2。

i=3 · 71 小于 75 → 不结算:负例分支:71 比栈顶(75),第 2 天还得继续等,什么都不结算,今天也开始等,压入 3。栈里现在两天 [2, 3],温度仍是底高顶低。

i=4 · 69 小于 71 → 不结算:69 比栈顶(71)还矮,照样不结算,压入 4。栈攒到 [2, 3, 4],温度 75 大于 71 大于 69,严格递减。

i=5 · 72 连弹两天:核心一步:72 一来,连续弹两天——先结算第 4 天 ans[4]=1,再结算第 3 天 ans[3]=2;直到栈顶第 2 天的 75 大于 72,停止弹出,压入今天 5。一个高温一次清掉好几笔账。

i=6 · 76 再连弹两天:76 是个大高温:先弹第 5 天 ans[5]=1,再弹第 2 天 ans[2]=4(等了整整 4 天),栈被清空。压入 6。

i=7 · 73 小于 76 → 不结算:最后一天 73 比栈顶(76)矮,不结算,压入 7。扫描到此结束。

收尾 · 栈里剩 [6,7]:扫描结束,栈里还剩第 6、7 天没等到更暖的,它们的答案保持初始 0。最终 [1,1,4,2,1,1,0,0]

凡是「为每个元素找右边第一个更大 / 更小的元素」,都用单调栈:每日温度、下一个更大元素、柱状图最大矩形、接雨水都是这一招的变体。

参考代码(Python)

Python
1ans = [0] * len(temps)
2stack = []                       # 存「还在等」的下标(单调递减)
3for i, t in enumerate(temps):
4    while stack and t > temps[stack[-1]]:   # 今天比栈顶更暖
5        j = stack.pop()              # 第 j 天等到了
6        ans[j] = i - j               # 天数差 = 今天 − 那天
7    stack.append(i)                  # 今天开始排队等更暖
8return ans

复杂度分析

  • 时间复杂度:O(n) —— 每个下标进栈一次、出栈一次,while 总弹出次数不超过 n
  • 空间复杂度:O(n) —— 最坏(温度递减)栈里装下全部 n 个下标

套路模板

记住骨架:栈存下标、新元素打破单调性就弹栈结算、再入栈。把比较的 大于 换成 小于,就从「下一个更大」变成「下一个更小」。

Python
1# 「为每个元素找右边第一个更大 / 更小」都套
2stack = []                       # 存还没找到答案的下标
3for i, x in enumerate(arr):
4    while stack and x > arr[stack[-1]]:   # 维持递减栈
5        j = stack.pop()
6        ans[j] = i - j               # 结算 j(天数差/距离)
7    stack.append(i)

易错点

  • 错误写法:栈里直接存温度值 temps[i]正确写法:栈里存下标 i,比较时再 temps[stack[-1]](答案要的是「等几天」即下标差 i−j,只存温度值就拿不到位置,算不出天数)
  • 错误写法:while 写成 if 只弹一次正确写法:用 while 连续弹出(一个高温可能让前面好几天同时等到,必须一次性弹光所有比它矮的栈顶,如 i=5 的 72 连弹第 4、第 3 天)
  • 错误写法:比较写成 大于等于(温度相等也弹)正确写法:只在严格 大于 时弹出(温度相等不算「更暖」,弹了会把等待天数算少一天)

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

下一题 →283. 移动零 ← 返回题库