1 题目
给定一个整数数组 temperatures ,表示每天的温度,返回一个数组 answer ,其中 answer[i] 是指对于第 i 天,下一个更高温度出现在几天后。如果气温在这之后都不会升高,请在该位置用 0 来代替。
示例 1:
输入: temperatures = [73,74,75,71,69,72,76,73]
输出: [1,1,4,2,1,1,0,0]
示例 2:
输入: temperatures = [30,40,50,60]
输出: [1,1,1,0]
示例 3:
输入: temperatures = [30,60,90]
输出: [1,1,0]
提示:
1 <= temperatures.length <= 10530 <= temperatures[i] <= 100
2 代码实现
cpp
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
int* dailyTemperatures(int* temperatures, int temperaturesSize, int* returnSize) {
// 设置返回数组大小
*returnSize = temperaturesSize;
// 初始化结果数组,默认值为0
int* answer = (int*)malloc(sizeof(int) * temperaturesSize);
for (int i = 0; i < temperaturesSize; i++) {
answer[i] = 0;
}
// 单调栈:存储温度数组的索引,维持栈内温度单调递减
int* stack = (int*)malloc(sizeof(int) * temperaturesSize);
int top = -1; // 栈顶指针,-1表示栈为空
for (int i = 0; i < temperaturesSize; i++) {
// 当栈非空且当前温度高于栈顶索引对应的温度时,弹出栈顶并计算天数
while (top != -1 && temperatures[i] > temperatures[stack[top]]) {
int prev_idx = stack[top--]; // 弹出栈顶索引
answer[prev_idx] = i - prev_idx; // 计算间隔天数
}
// 当前索引入栈
stack[++top] = i;
}
free(stack); // 释放栈内存
return answer;
}
cpp
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
int* dailyTemperatures(int* temperatures, int temperaturesSize, int* returnSize) {
// 1. 初始化返回结果相关
*returnSize = temperaturesSize; // 设置返回数组的大小
int* answer = (int*)malloc(sizeof(int) * temperaturesSize);
for (int i = 0; i < temperaturesSize; i++) {
answer[i] = 0; // 默认值为0(没有更高温度)
}
// 2. 初始化单调栈(存储温度的索引)
int* stack = (int*)malloc(sizeof(int) * temperaturesSize);
int top = -1; // 栈顶指针,-1表示栈为空
// 3. 遍历每个温度,分情况处理栈顶元素与当前元素的关系
for (int i = 0; i < temperaturesSize; i++) {
// 当前元素:temperatures[i],当前索引:i
int current_temp = temperatures[i];
// 栈不为空时,才需要比较栈顶元素
while (top != -1) {
int stack_top_idx = stack[top]; // 栈顶索引
int stack_top_temp = temperatures[stack_top_idx]; // 栈顶对应的温度
// 情况1:当前温度 > 栈顶温度 → 栈顶元素找到下一个更高温度
if (current_temp > stack_top_temp) {
answer[stack_top_idx] = i - stack_top_idx; // 计算天数差
top--; // 弹出栈顶(已处理完)
}
// 情况2:当前温度 == 栈顶温度 → 栈顶元素未找到更高温度,不弹出
else if (current_temp == stack_top_temp) {
break; // 停止弹出,当前温度不满足"更高",无需继续检查
}
// 情况3:当前温度 < 栈顶温度 → 栈顶元素未找到更高温度,不弹出
else { // current_temp < stack_top_temp
break; // 停止弹出,当前温度更小,无需继续检查
}
}
// 无论哪种情况,当前索引都要入栈(等待后续更高温度)
top++;
stack[top] = i;
}
// 4. 释放资源并返回结果
free(stack);
return answer;
}
我的乱乱的思路:
c语言不是很会写,元素入栈,单调,然后数组索引其实就是有无高温天气,不是很难,主要是不会写,数组索引要处理一下,然后和原来的数组对应。
原数组,进栈出栈得到单调栈,温度天数索引数组,不会写,也不知道这个怎么实现,感觉理论上有这种下一个最大或者最小的算法题就是单调栈,但不会写具体栈和数组的实现,语法也不熟悉。

还得是代码随想录讲的,豁然开朗了!
代码随想录讲解传送门
【单调栈,你该了解的,这里都讲了!LeetCode:739.每日温度】
按照代码随想录分三种情况处理的解法
虽然冗余但是好理解。
为了让思路更清晰,我们明确区分栈顶元素与当前元素的三种关系(大于、等于、小于),并在代码中对应处理。核心逻辑依然是单调栈,但会把每种情况的判断写得更明确。
完整代码(分情况处理)
cpp
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
int* dailyTemperatures(int* temperatures, int temperaturesSize, int* returnSize) {
// 1. 初始化返回结果相关
*returnSize = temperaturesSize; // 设置返回数组的大小
int* answer = (int*)malloc(sizeof(int) * temperaturesSize);
for (int i = 0; i < temperaturesSize; i++) {
answer[i] = 0; // 默认值为0(没有更高温度)
}
// 2. 初始化单调栈(存储温度的索引)
int* stack = (int*)malloc(sizeof(int) * temperaturesSize);
int top = -1; // 栈顶指针,-1表示栈为空
// 3. 遍历每个温度,分情况处理栈顶元素与当前元素的关系
for (int i = 0; i < temperaturesSize; i++) {
// 当前元素:temperatures[i],当前索引:i
int current_temp = temperatures[i];
// 栈不为空时,才需要比较栈顶元素
while (top != -1) {
int stack_top_idx = stack[top]; // 栈顶索引
int stack_top_temp = temperatures[stack_top_idx]; // 栈顶对应的温度
// 情况1:当前温度 > 栈顶温度 → 栈顶元素找到下一个更高温度
if (current_temp > stack_top_temp) {
answer[stack_top_idx] = i - stack_top_idx; // 计算天数差
top--; // 弹出栈顶(已处理完)
}
// 情况2:当前温度 == 栈顶温度 → 栈顶元素未找到更高温度,不弹出
else if (current_temp == stack_top_temp) {
break; // 停止弹出,当前温度不满足"更高",无需继续检查
}
// 情况3:当前温度 < 栈顶温度 → 栈顶元素未找到更高温度,不弹出
else { // current_temp < stack_top_temp
break; // 停止弹出,当前温度更小,无需继续检查
}
}
// 无论哪种情况,当前索引都要入栈(等待后续更高温度)
top++;
stack[top] = i;
}
// 4. 释放资源并返回结果
free(stack);
return answer;
}
逐情况详细讲解
核心逻辑回顾
单调栈的作用是暂存 "尚未找到下一个更高温度" 的天数索引 ,栈内索引对应的温度保持单调递减(从栈底到栈顶温度越来越小)。遍历每个温度时,通过比较当前温度与栈顶温度的关系,决定是否处理栈顶元素。
三种情况的处理逻辑
1. 情况 1:当前温度 > 栈顶温度(current_temp > stack_top_temp)
-
含义:栈顶索引对应的那一天,终于找到了 "下一个更高温度"(就是当前天)。
-
处理:
- 计算天数差:
当前索引 i - 栈顶索引 stack_top_idx,存入answer[stack_top_idx]。 - 弹出栈顶元素(
top--),因为它已经找到结果,不需要再留在栈里。 - 继续循环检查新的栈顶元素(可能当前温度也比新栈顶高,需要继续处理)。
举例 :栈顶是索引 4(温度 69),当前是索引 5(温度 72)。72 > 69,所以
answer[4] = 5-4=1,弹出索引 4,再检查新栈顶(索引 3,温度 71),72 > 71,继续处理。 - 计算天数差:
2. 情况 2:当前温度 == 栈顶温度(current_temp == stack_top_temp)
-
含义:当前温度与栈顶温度相等,不满足 "更高" 的条件,栈顶元素还没找到结果。
-
处理:
- 停止循环(
break),不弹出栈顶元素。 - 因为即使继续检查栈内其他元素,当前温度也不满足 "更高",无需再比较。
举例:栈顶是索引 2(温度 75),当前是索引 x(温度 75)。75 == 75,栈顶元素(索引 2)的下一个更高温度不是当前天,所以不处理,直接退出循环。
- 停止循环(
3. 情况 3:当前温度 < 栈顶温度(current_temp < stack_top_temp)
-
含义:当前温度比栈顶温度低,栈顶元素的 "下一个更高温度" 肯定不是当前天(可能在更后面)。
-
处理:
- 停止循环(
break),不弹出栈顶元素。 - 因为栈内元素是单调递减的,栈顶后面的元素温度比栈顶还小,当前温度比栈顶小,自然也比后面的元素小,无需继续比较。
举例:栈顶是索引 2(温度 75),当前是索引 3(温度 71)。71 < 75,栈顶元素(索引 2)的下一个更高温度不在当前天,所以不处理,退出循环。
- 停止循环(
最后一步:当前索引入栈
无论上述哪种情况处理完毕后,都要把当前索引 i 入栈(stack[++top] = i)。因为当前天也需要等待 "它自己的下一个更高温度" 出现,所以暂时存到栈里。
为什么这样处理更清晰?
- 把三种关系(>、==、<)明确拆分,避免了原来 "合并判断" 的简洁写法可能带来的困惑。
- 每种情况的处理逻辑独立,更容易理解 "为什么栈顶要弹出""为什么要停止循环"。
- 本质上和精简版本的逻辑一致,但通过显式的条件判断,让初学者能更直观地看到单调栈的维护过程。
总结
这道题的核心是用单调栈 "记住" 还没找到结果的天数索引,通过比较当前温度与栈顶温度的关系,逐步确定每个天数的结果。三种情况的处理都是为了维持栈的 "单调递减" 特性,确保每个元素只需要入栈和出栈一次,从而实现高效的 O (n) 时间复杂度。
ai给的简化解法(升级版)
首先你提到 "用单调栈,处理数组索引,找到下一个更高温度的天数",这个思路是完全正确的!
不过可能对 "栈怎么存索引""怎么通过索引计算天数" 这些细节有疑问,我们慢慢理清楚。
一、先理解题目要做什么
给一个温度数组,比如 [73,74,75,71,69,72,76,73],我们要返回一个数组 answer,其中 answer[i] 表示:第 i 天之后,过几天会出现比 temperatures[i] 更高的温度。如果一直没有,就填 0。
比如第 0 天温度是 73,下一个更高的是第 1 天的 74,所以 answer[0] = 1-0 = 1;第 2 天温度是 75,下一个更高的是第 6 天的 76,所以 answer[2] = 6-2 = 4。
二、为什么用 "单调栈"?
你已经想到用单调栈,这非常棒!因为我们要找 "每个元素后面第一个比它大的元素",这种 "找下一个更大元素" 的问题,单调栈是最高效的解法(时间复杂度 O (n))。
如果不用单调栈,可能会想到 "暴力解法":对每个 i,往后遍历找第一个比 temperatures[i] 大的元素,记录天数。但这样时间复杂度是 O (n²),如果数组很长(比如 10^5 个元素),会超时。所以单调栈是最优选择。
三、代码逐行拆解(结合你的思路)
我们就按你提供的代码,一步一步看每句代码的作用,以及为什么这么写。
1. 初始化返回值相关
cpp
*returnSize = temperaturesSize; // 设置返回数组的大小
int* answer = (int*)malloc(sizeof(int) * temperaturesSize); // 申请结果数组的内存
for (int i = 0; i < temperaturesSize; i++) {
answer[i] = 0; // 初始化结果数组为0(默认没有更高温度)
}
- 为什么要初始化
answer为 0?因为如果某个温度后面一直没有更高的,结果就是 0,提前初始化可以省去后续处理。 malloc是申请动态内存,因为函数返回的数组需要在函数外释放,所以必须用malloc而不是局部数组。
2. 初始化单调栈
cpp
int* stack = (int*)malloc(sizeof(int) * temperaturesSize); // 栈的内存
int top = -1; // 栈顶指针,-1表示栈为空
- 这里的栈存的是 "温度数组的索引"(比如 0、1、2...),而不是温度值本身。这是你思路的核心,非常关键!因为我们需要用索引计算 "天数差"(比如第 i 天和第 j 天的差是 j-i)。
- 为什么栈的大小是
temperaturesSize?因为最坏情况下,所有元素都会进栈(比如温度一直递减,如 [5,4,3,2,1]),所以最大需要这么多空间。 top = -1是栈的常用初始化方式:top表示栈顶的位置,-1 说明栈里没有元素。
3. 遍历温度数组(核心逻辑)
cpp
for (int i = 0; i < temperaturesSize; i++) { // i 是当前天的索引
// 当栈不为空,且当前温度 > 栈顶索引对应的温度时
while (top != -1 && temperatures[i] > temperatures[stack[top]]) {
int prev_idx = stack[top--]; // 弹出栈顶索引(之前的某一天)
answer[prev_idx] = i - prev_idx; // 计算天数差
}
// 当前索引入栈
stack[++top] = i;
}
这部分是最关键的,我们结合例子(temperatures = [73,74,75,71,69,72,76,73])一步步模拟,你就明白了。
步骤 1:i=0(当前天是第 0 天,温度 73)
- 栈是空的(
top=-1),所以不进入while循环。 - 执行
stack[++top] = i:top从 -1 变成 0,栈里存[0](表示第 0 天的索引)。
步骤 2:i=1(当前天是第 1 天,温度 74)
- 栈不为空(
top=0),栈顶索引是 0,对应的温度是 73。当前温度 74 > 73,满足while条件。- 弹出栈顶:
prev_idx = stack[0] = 0,top变回 -1。 - 计算天数差:
answer[0] = 1 - 0 = 1(第 0 天的结果确定了)。
- 弹出栈顶:
while循环结束(栈空了),执行stack[++top] = 1:栈里存[1]。
步骤 3:i=2(当前天是第 2 天,温度 75)
- 栈顶索引是 1,对应温度 74。当前温度 75 > 74,进入
while。- 弹出栈顶:
prev_idx=1,top=-1。 - 计算:
answer[1] = 2-1=1(第 1 天的结果确定了)。
- 弹出栈顶:
- 栈空,执行
stack[++top] = 2:栈里存[2]。
步骤 4:i=3(当前天是第 3 天,温度 71)
- 栈顶索引是 2,对应温度 75。当前温度 71 < 75,不满足
while条件。 - 执行
stack[++top] = 3:栈里存[2,3]。
步骤 5:i=4(当前天是第 4 天,温度 69)
- 栈顶索引是 3,对应温度 71。69 < 71,不进入
while。 - 入栈:栈里存
[2,3,4]。
步骤 6:i=5(当前天是第 5 天,温度 72)
- 栈顶索引是 4,对应温度 69。72 > 69,进入
while:- 弹出 4,
answer[4] = 5-4=1(第 4 天结果确定)。栈现在是[2,3]。
- 弹出 4,
- 栈顶索引是 3,对应温度 71。72 > 71,继续
while:- 弹出 3,
answer[3] =5-3=2(第 3 天结果确定)。栈现在是[2]。
- 弹出 3,
- 栈顶索引是 2,对应温度 75。72 < 75,
while结束。 - 入栈:栈里存
[2,5]。
步骤 7:i=6(当前天是第 6 天,温度 76)
- 栈顶索引是 5,对应温度 72。76 >72,进入
while:- 弹出 5,
answer[5] =6-5=1(第 5 天结果确定)。栈现在是[2]。
- 弹出 5,
- 栈顶索引是 2,对应温度 75。76>75,继续
while:- 弹出 2,
answer[2] =6-2=4(第 2 天结果确定)。栈空了。
- 弹出 2,
while结束,入栈:栈里存[6]。
步骤 8:i=7(当前天是第 7 天,温度 73)
- 栈顶索引是 6,对应温度 76。73 <76,不进入
while。 - 入栈:栈里存
[6,7]。
遍历结束后,栈里剩下的 6 和 7,它们对应的 answer 还是初始的 0(因为后面没有更高温度了)。最终 answer 就是 [1,1,4,2,1,1,0,0],和示例一致。
4. 释放内存并返回
cpp
free(stack); // 释放栈的内存(栈只是临时用的,不用返回)
return answer; // 返回结果数组
- 为什么要释放
stack?因为stack是在函数内malloc的,不用了就要释放,避免内存泄漏。 answer不能在这里释放,因为要返回给调用者使用,调用者会负责释放。
四、可能的误区(结合你的思路)
你提到 "数组索引要处理一下,然后和原来的数组对应",这其实是核心点,但初学者可能会有这些疑问:
-
**为什么栈存索引而不是温度值?**因为我们需要计算 "天数差"(比如第 i 天和第 j 天的差是 j-i),如果存温度值,就不知道它是哪一天的了,无法计算差。所以存索引才能关联到具体的天数。
-
**为什么栈要保持 "单调递减"?**栈里的索引对应的温度是越来越小的(从栈底到栈顶)。这样当遇到一个更高的温度时,栈顶的索引对应的温度一定是目前最小的,只要当前温度比它大,就能确定栈顶索引的 "下一个更高温度" 就是当前天。如果不保持递减,就需要多次回溯,效率变低。
-
**为什么
while循环要用 "弹出栈顶" 的操作?**因为当前温度可能比栈里多个元素都高。比如当前温度是 76,栈里有 [2,5](对应温度 75、72),76 比 72 大,处理完 5 之后,还要检查 2(75),因为 76 也比 75 大,所以需要循环弹出,直到栈顶温度不小于当前温度。
五、总结
这道题的核心就是用 "单调栈存索引",通过维护栈的 "单调递减" 特性,高效找到每个温度的 "下一个更高温度"。步骤可以简化为:
- 遍历每个温度(当前天 i)。
- 只要栈里有元素,且当前温度比栈顶索引的温度高,就弹出栈顶,计算天数差(i - 栈顶索引),存到结果数组。
- 把当前天的索引入栈。
- 遍历结束后,结果数组中没被修改的位置就是 0(默认值)。
这样每个元素最多入栈和出栈一次,时间效率很高,适合处理大规模数据。多手动模拟几遍栈的变化,就能完全掌握了!