给定一个整数数组 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
1. 生活案例:排队买奶茶
想象你在一家网红奶茶店排队:
-
规则:每个人手里都有一个号码牌(代表温度)。你想知道,在你后面排队的人里,第一个比你号码大的人离你有多远。
-
过程:
- 你站在队伍里等。
- 新来一个人,如果他的号码比你小,你也得继续等,他也得在你后面等。
- 新来一个人,如果他的号码比你大,恭喜你!你等到了。你算出你们之间的距离(比如他是你后面第3个),然后你就可以拿着奶茶离开了。
这个“等待”的队伍,在编程里就是单调栈。
2. 代码实现与详细注释
这是你图片中的代码,我为你加上了结合生活案例的详细中文注释:
JavaScript
/**
* @param {number[]} temperatures - 每天的温度数组 (每个人手里的号码牌)
* @return {number[]} - 返回一个数组,表示还要等几天才有更高温
*/
var dailyTemperatures = function(temperatures) {
let stack = []; // 【等候区】:存放还没找到“更高温”的那些天的【下标】
let n = temperatures.length;
let result = new Array(n).fill(0); // 【结果单】:默认都是0,如果后面没等到的,就留作0
for (let i = 0; i < n; i++) {
// 当【等候区】有人,且【今天新来的温度】比【等候区最后一个人】的温度高时
// 意味着等候区的人终于等到了他的“温暖”
while (stack.length !== 0 && temperatures[i] > temperatures[stack[stack.length - 1]]) {
// 1. 把等到了的那个人从等候区请出来 (出栈)
let prevIndex = stack.pop();
// 2. 计算那个人等了几天 (今天的下标 - 那人的下标)
result[prevIndex] = i - prevIndex;
// 继续检查等候区里的前一个人,看看今天是不是也比他高
}
// 今天的温度暂时还没找到比它更高的,或者刚处理完别人,今天自己也要进【等候区】排队
stack.push(i);
}
return result;
};
3. 核心原理解析
为什么用栈(Stack)?
- 后进先出:在温度数组中,我们总是先拿“今天”的温度去和“最近还没找到更高温”的那几天比。
- 保持单调性:在这个栈里,温度永远是从底到顶递减的。一旦来了一个高个子(高温),它就会把栈顶那些矮个子(低温)全部“解救”出来。
运行轨迹示例:
假设温度是 [73, 74, 75, 71, 69, 72]:
-
73 进栈。
-
74 来了,比 73 高。73 出栈,记录结果:
74(位置1) - 73(位置0) = 1。然后 74 进栈。 -
75 来了,比 74 高。74 出栈,记录结果:
2 - 1 = 1。然后 75 进栈。 -
71 来了,比 75 低。71 进栈(等候区)。
-
69 来了,比 71 低。69 进栈(等候区)。此时栈里有:
[75, 71, 69]。 -
72 来了!
- 比 69 高:69 出栈,计算
5 - 4 = 1。 - 比 71 高:71 出栈,计算
5 - 3 = 2。 - 比 75 低:72 进栈。
- 比 69 高:69 出栈,计算
复杂度
- 时间复杂度:。虽然有嵌套循环,但每个元素最多进栈一次、出栈一次。
- 空间复杂度:。最坏情况下,所有温度都在栈里排队。
这种解法比暴力双循环()快得多,尤其是在处理像 10 万条数据这种大规模输入时。