力扣刷题#24-0739-每日温度
力扣刷题#24-0739-每日温度
题目
给定一个整数数组 temperatures,表示每天的温度。返回一个数组 answer,其中 answer[i] 是指对于第 i 天,下一个更高温度出现在几天后。如果之后都不会升高,用 0 代替。
输入: temperatures = [73,74,75,71,69,72,76,73]
输出: [1,1,4,2,1,1,0,0]
输入: temperatures = [30,40,50,60]
输出: [1,1,1,0]
我的思路
核心直觉:从右往左扫,用栈维护"候选者"
看到"下一个更大的"这类字眼,直觉告诉我应该用栈。但要怎么扫、栈里存什么?
从右往左遍历,因为"右边"的信息对左边的答案有用——我先知道右边的情况,再回来填左边的答案。
栈的作用:保存那些比当前温度高、且位置在右边的日子。对"左边的每一天"来说,这些就是"右侧第一个更热的日子"的候选者。
栈里的数据需要满足一个性质:从栈底到栈顶,温度严格递减。如果有个日子温度又低位置又远,那它永远不会被任何"左边日子"选中——弹掉。
算法三步走
从右往左遍历每一天 i:
① 弹:while (栈不空 且 栈顶温度 ≤ 今天温度) → pop
理由:今天的温度更高且更靠左,被弹掉的日子比今天冷、比今天远,
以后左边日子找"右边第一个更热的",今天一定抢先被选中
② 算:if (栈不空) → answer[i] = 栈顶索引 - i
栈顶就是弹剩下的"第一个比今天热的日子"
③ 压:s.push(i),今天的索引入栈,等左边更冷的日子来查
一步步走通
[73, 74, 75, 71, 69, 72, 76, 73],从右往左:
| i | 当天温度 | ① 弹栈 | 弹后栈 | ② answer[i] | ③ 压后栈 |
|---|---|---|---|---|---|
| 7 | 73 | 栈空,跳过 | [] |
0 | [7] |
| 6 | 76 | 73≤76→弹7 | [] |
0 | [6] |
| 5 | 72 | 76>72→不弹 | [6] |
6-5=1 | [6,5] |
| 4 | 69 | 72>69→不弹 | [6,5] |
5-4=1 | [6,5,4] |
| 3 | 71 | 69≤71→弹4;72>71→停 | [6,5] |
5-3=2 | [6,5,3] |
| 2 | 75 | 71≤75→弹3;72≤75→弹5;76>75→停 | [6] |
6-2=4 | [6,2] |
| 1 | 74 | 75>74→不弹 | [6,2] |
2-1=1 | [6,2,1] |
| 0 | 73 | 74>73→不弹 | [6,2,1] |
1-0=1 | [6,2,1,0] |
输出:[1, 1, 4, 2, 1, 1, 0, 0] ✅
关键观察:栈里的温度始终从底到顶递减。以 i=0 时的栈为例:
栈底 → 索引6(温度76) → 索引2(温度75) → 索引1(温度74) → 索引0(温度73) ← 栈顶
最热 次热 次次热 当前
这就是"单调栈"名字的由来。
为什么要存索引而不是存温度?
我的第一反应是栈里要不要存 pair<温度, 索引>。后来想通了——答案是"几天后",需要算索引差,所以索引必须存。而温度随时能从原数组查到:
temperatures[s.top()] // 栈顶对应的温度,O(1)
存温度就冗余了。栈里只存 int 索引即可。
我的 AC 代码
class Solution {
public:
vector<int> dailyTemperatures(vector<int>& temperatures) {
stack<int> s;
int len = temperatures.size();
vector<int> an(len, 0);
for (int i = len - 1; i >= 0; i--) {
while (!s.empty() && temperatures[i] >= temperatures[s.top()]) {
s.pop();
}
if (!s.empty()) {
an[i] = s.top() - i;
}
s.push(i);
}
return an;
}
};
代码逐段解析
第 5 行:初始化 answer 数组
vector<int> an(len, 0);
len 个 0 打底。后面只有找到"右侧第一个更热的"才覆盖,找不到的保持 0——刚好满足题目要求。
第 6-7 行:while 弹栈
while (!s.empty() && temperatures[i] >= temperatures[s.top()]) {
s.pop();
}
两个注意点:
!s.empty()必须写在前面——&&从左往右算,栈空时先取s.top()就崩了。- 用
>=不用>:如果右边有个相同温度的日子,它更靠右 → 对"左边"来说不是"更热的" → 也得弹掉。
第 8-11 行:if 算答案 + push
if (!s.empty()) {
an[i] = s.top() - i;
}
s.push(i);
if 条件和 s.push(i) 是分开的——不管今天有没有找到右侧更热的日子,今天的索引都必须进栈,等着被左边更冷的日子查询。
踩坑记录
坑 1:s.push(i) 写在了 if 里面
// ❌ 第一版
if (!s.empty() && temperatures[i] < temperatures[s.top()]) {
an[i] = s.top() - i;
s.push(i); // ← push 受 if 约束
}
后果:while 弹空栈后,s.empty() 为 true,if 不走 → s.push(i) 不执行 → 栈永远是空的 → 后面所有 answer[i] 全是 0。
修复:s.push(i) 放到 if 外面,作为每轮必定执行的第三步。
坑 2:vector::insert 误用
// ❌
an.insert(s.top() - i); // insert(pos, val) 需要两个参数
// ✅
an[i] = s.top() - i; // 直接按下标赋值
insert 是"在指定位置插入"不是你想要的"填指定位置"。数组 an 已提前分配好 len 个位置,直接用 an[i] = ... 赋值即可。
坑 3:&& 短路求值顺序
// ❌ 先算 s.top() 后判空
while (temperatures[i] >= temperatures[s.top()] && !s.empty())
// ✅ 先判空
while (!s.empty() && temperatures[i] >= temperatures[s.top()])
&& 从左往右计算。栈空时前者先执行 s.top() → 空栈取顶 → 崩溃。
复杂度分析
| 维度 | 值 | 说明 |
|---|---|---|
| 时间复杂度 | O(n) | 每个索引入栈一次、出栈最多一次 |
| 空间复杂度 | O(n) | 栈最多存 n 个索引 |
关键点总结
| 关键点 | 说明 |
|---|---|
| 遍历方向 | 从右往左,先知道右边才能填左边 |
| 栈存什么 | 只存索引,温度通过数组查 |
| 弹栈条件 | 栈顶温度 ≤ 今天温度 → 弹掉(更冷且更远 = 没用) |
| 单调性 | 栈从底到顶温度严格递减(单调栈) |
| push 时机 | 无论有没有答案,每轮都必须 push |
本文档由 AI 辅助生成,作者提供问题,思路和代码,AI仅负责文本修饰,综合获得以上内容。

浙公网安备 33010602011771号