每日温度 图解题解
每天要等几天才会更热?单调栈一次扫描,温度进来时顺手把答案一口气全填了。
栈里存的是还没找到「更热那天」的日子的**下标**,从底到顶对应递减温度。新温度进来,只要它比栈顶那个下标对应的温度高,就把栈顶弹出结算:答案 = 当前下标 − 弹出的下标,算的就是等了几天。弹完如果还比新栈顶高,继续弹、继续填答案;弹完或栈空后,把**当前下标**压进去,等着将来更高的温度来叫醒自己。存下标而非温度,是因为「等了几天」要用两个位置做减法,只有下标才能算差值。
这道题到底在问什么
- 输入
- temperatures=[73,74,75,71,69,72,76,73]
- 输出
- [1,1,4,2,1,1,0,0]
最优解:为什么这么做
一句话答案:LeetCode 739 每日温度的最优解是单调递减栈:栈里存还没等到更高温的那些天的下标,新来一个温度就把比它低的栈顶逐个弹出结算,等待天数就是下标差 i - j。每个下标进出栈各一次,时间 O(n)、空间 O(n),比逐天向右扫的 O(n²) 暴力快一个数量级。
每日温度这道题在问什么
给一个数组 temperatures 记录每天气温,要求对每一天算出:再过几天会出现第一个比今天更高的温度,如果之后再也没有更高温就填 0。剥掉温度的外衣,它就是经典的「下一个更大元素」问题的距离版——对每个位置找右边第一个严格更大的元素,只是答案要的不是那个值,而是两者隔了几个位置。
为什么逐天向右扫的暴力会慢
最直觉的做法是对每一天都向右线性扫描,撞到第一个更高温为止,最坏 O(n²)。慢在重复劳动:一段连续降温的日子里,每一天都要把后面同样的区间再扫一遍。
换个视角看,某一天的答案要等到「未来某天」才揭晓。与其让每一天主动向右找,不如反过来:让还没等到答案的日子排队挂起,每来一个新温度,就检查队伍里有谁的答案在此刻揭晓,统一结算。这样每天只被处理常数次,扫描的浪费就消失了。
为什么栈里的温度天然是递减的
用一个栈保存「尚未找到答案」的下标。新温度 t 到来时,只要栈顶那天的温度比 t 低,它的答案就是今天,弹出结算;重复直到栈顶不再比 t 低,再把今天的下标压入。
注意一个自动成立的性质:留在栈里的温度从底到顶一定递减——因为任何比后来者低的栈顶都会在那一刻被弹掉,能留下的只有更高的。这个单调性正是效率的来源:结算时只需盯着栈顶弹,一旦栈顶不低于当前温度就能立刻停手,因为更深处的温度只会更高,它们还得继续等。这也是「单调栈」这个名字的含义。
弹出时下标差 i - j 为什么就是正确答案
当第 i 天把栈里的第 j 天弹出时,i 恰好是 j 之后第一个更高温的日子:j 与 i 之间的每一天都曾经入栈,却没能把 j 弹出,说明它们的温度都不超过第 j 天——中间没有任何一天满足条件,所以等待天数就是 i - j,不多不少。这也解释了栈里为什么必须存下标而不是温度:答案是位置差,只有温度算不出天数。
复杂度怎么数,边界坑在哪
时间 O(n):虽然循环里套着 while,但每个下标一生至多入栈一次、出栈一次,总操作次数是 2n 级别。空间 O(n):最坏温度一路走低,所有下标都压在栈里。
两个易错点:一是弹栈条件必须是严格大于,温度相等不算「更高温」,相等的那天还得继续等;二是扫完后仍留在栈里的日子,到最后也没等来更高温,它们的答案就是初始化的 0,不需要再补处理。
▶ 动画逐步走查(共 24 步)——想跟着动画一帧帧对照就展开
- 3记住这条:栈顶一旦被「踩过头」就弹出结算,差值就是答案。
- 4轮到第 0 天(73°)。栈是空的,没有更早的天在等更高温,直接进栈。
- 5没有更低的栈顶要结算了,把第 0 天(73°)压入栈顶,等后面更热的一天来踩它。此刻栈里温度始终是从底到顶递减的。
- 6轮到第 1 天(74°)。先看栈顶第 0 天(73°):今天更热,栈顶终于等到了更高温。
- 7第 1 天(74°)比第 0 天(73°)高,第 0 天等到了:弹出它,等待天数 = 1 − 0 = 1。继续看新栈顶还会不会被踩过头。
- 8没有更低的栈顶要结算了,把第 1 天(74°)压入栈顶,等后面更热的一天来踩它。此刻栈里温度始终是从底到顶递减的。
- 9轮到第 2 天(75°)。先看栈顶第 1 天(74°):今天更热,栈顶终于等到了更高温。
- 10第 2 天(75°)比第 1 天(74°)高,第 1 天等到了:弹出它,等待天数 = 2 − 1 = 1。继续看新栈顶还会不会被踩过头。
- 11没有更低的栈顶要结算了,把第 2 天(75°)压入栈顶,等后面更热的一天来踩它。此刻栈里温度始终是从底到顶递减的。
- 12轮到第 3 天(71°)。先看栈顶第 2 天(75°):今天没它热,它继续等,今天先入栈排队。
- 13没有更低的栈顶要结算了,把第 3 天(71°)压入栈顶,等后面更热的一天来踩它。此刻栈里温度始终是从底到顶递减的。
- 14轮到第 4 天(69°)。先看栈顶第 3 天(71°):今天没它热,它继续等,今天先入栈排队。
- 15没有更低的栈顶要结算了,把第 4 天(69°)压入栈顶,等后面更热的一天来踩它。此刻栈里温度始终是从底到顶递减的。
- 16轮到第 5 天(72°)。先看栈顶第 4 天(69°):今天更热,栈顶终于等到了更高温。
- 17第 5 天(72°)比第 4 天(69°)高,第 4 天等到了:弹出它,等待天数 = 5 − 4 = 1。继续看新栈顶还会不会被踩过头。
- 18第 5 天(72°)比第 3 天(71°)高,第 3 天等到了:弹出它,等待天数 = 5 − 3 = 2。继续看新栈顶还会不会被踩过头。
- 19没有更低的栈顶要结算了,把第 5 天(72°)压入栈顶,等后面更热的一天来踩它。此刻栈里温度始终是从底到顶递减的。
- 20轮到第 6 天(76°)。先看栈顶第 5 天(72°):今天更热,栈顶终于等到了更高温。
- 21第 6 天(76°)比第 5 天(72°)高,第 5 天等到了:弹出它,等待天数 = 6 − 5 = 1。继续看新栈顶还会不会被踩过头。
- 22第 6 天(76°)比第 2 天(75°)高,第 2 天等到了:弹出它,等待天数 = 6 − 2 = 4。继续看新栈顶还会不会被踩过头。
- 23没有更低的栈顶要结算了,把第 6 天(76°)压入栈顶,等后面更热的一天来踩它。此刻栈里温度始终是从底到顶递减的。
- 24轮到第 7 天(73°)。先看栈顶第 6 天(76°):今天没它热,它继续等,今天先入栈排队。
- 25没有更低的栈顶要结算了,把第 7 天(73°)压入栈顶,等后面更热的一天来踩它。此刻栈里温度始终是从底到顶递减的。
- 26数组扫完,栈里剩下的第 6、7 天到最后也没遇到更高温,它们的 answer = 0。最终 answer = [1,1,4,2,1,1,0,0]。
⚠️ 容易写错的地方
✗ 错:栈里存温度
✓ 对:栈里存下标
答案要的是天数差 i−j,没下标算不出来
✗ 错:用 ≥ 弹栈
✓ 对:严格 > 才弹栈
相等不算「更高温」,等于的那天还得继续等
✗ 错:忘了剩在栈里的
✓ 对:它们 answer 保持 0
到末尾仍没更高温,初始 0 正好
完整代码(Python / C++ / Java)
Python
def dailyTemperatures(T):
ans = [0] * len(T)
stack = [] # 存下标,温度递减
for i, t in enumerate(T):
while stack and t > T[stack[-1]]:
j = stack.pop()
ans[j] = i - j
stack.append(i)
return ansC++
vector<int> dailyTemperatures(vector<int>& T){
int n = T.size();
vector<int> ans(n, 0);
stack<int> st; // 存下标
for(int i = 0; i < n; i++){
while(!st.empty() && T[i] > T[st.top()]){
int j = st.top(); st.pop();
ans[j] = i - j;
}
st.push(i);
}
return ans;
}Java
public int[] dailyTemperatures(int[] T) {
int n = T.length;
int[] ans = new int[n];
Deque<Integer> st = new ArrayDeque<>(); // 存下标
for (int i = 0; i < n; i++) {
while (!st.isEmpty() && T[i] > T[st.peek()]) {
int j = st.pop();
ans[j] = i - j;
}
st.push(i);
}
return ans;
}复杂度
时间
O(n)
每个下标进出栈各一次
空间
O(n)
最坏全部递减,栈装下所有下标
看不够?换成动画再走一遍
上面的推演每一步都对应一帧动画。点开交互动画版,能一步步看着 每日温度 的数据怎么变、指针怎么走,还能切 Python / Java / C++ 跟着练。
面试官可能追问
为什么单调栈能做到 O(n)?+
每个下标最多入栈一次、出栈一次,总操作是线性的,远好于暴力的 O(n²)。
如果改成「下一个更高温的温度值」呢?+
同一套栈,弹出时记录 T[i] 而不是 i−j 即可(即「下一个更大元素」模板)。
想听吴师兄把这道题讲给你听?
文字版和动画都随便看。开通图解算法年卡,可以听吴师兄把 每日温度 一步步讲透(全站已上线 905 份讲透,持续扩充), 卡住的地方还有 AI 私教小欧就着动画帮你拆到懂。
本平台为独立第三方培训机构,与华为技术有限公司无任何关联;课程的服务内容与权益以购买协议为准,学习效果因个人情况而异。「华为 OD」「华为可信」等仅为对岗位与考试方向的客观描述,相关商标归各自权利人所有。