题目
题目来源:力扣(LeetCode)
请根据每日 气温 列表 temperatures ,请计算在每一天需要等几天才会有更高的温度。如果气温在这之后都不会升高,请在该位置用 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]
思路分析
对题目的理解
给定列表 temperatures = [73, 74, 75, 71, 69, 72, 76, 73],为啥输出就是 [1, 1, 4, 2, 1, 1, 0, 0] ?
下面来一个个进行解释。
对于输入 73,它需要 经过一天 才能等到温度的升高,也就是在第二天的时候,温度升高到 74 ,所以对应的结果是 1。
对于输入 74,它需要 经过一天 才能等到温度的升高,也就是在第三天的时候,温度升高到 75 ,所以对应的结果是 1。
对于输入 75,它经过 1 天后发现温度是 71,没有超过它,继续等,一直 等了四天,在第七天才等到温度的升高,温度升高到 76 ,所以对应的结果是 4 。
对于输入 71,它经过 1 天后发现温度是 69,没有超过它,继续等,一直 等了两天,在第六天才等到温度的升高,温度升高到 72 ,所以对应的结果是 2 。
对于输入 69,它 经过一天 后发现温度是 72,已经超过它,所以对应的结果是 1 。
对于输入 72,它 经过一天 后发现温度是 76,已经超过它,所以对应的结果是 1 。
对于输入 76,后续 没有温度 可以超过它,所以对应的结果是 0 。
对于输入 73,后续 没有温度 可以超过它,所以对应的结果是 0 。
解法
维护一个存储下标的单调栈,从栈底到栈顶的下标对应的温度列表中的温度依次递减。如果一个下标在单调栈里,则表示尚未找到下一次温度更高的下标。
遍历整个温度列表,如果栈不空,且当前数字大于栈顶元素,取出栈顶元素,由于当前数字大于栈顶元素的数字,而且一定是第一个大于栈顶元素的数,直接求出下标差就是二者的距离。
继续看新的栈顶元素,直到当前数字小于等于栈顶元素停止,然后将数字入栈,这样就可以一直保持递减栈,且每个数字和第一个大于它的数的距离也可以算出来。
以下用一个具体的例子帮助读者理解单调栈。对于温度列表[73,74,75,71,69,72,76,73],单调栈 stack 的初始状态为空,答案 ans 的初始状态是 [0,0,0,0,0,0,0,0],按照以下步骤更新单调栈和答案,其中单调栈内的元素都是下标,括号内的数字表示下标在温度列表中对应的温度。
当 i=0 时,单调栈为空,因此将 0 进栈。
- stack=[0(73)]
- ans=[0,0,0,0,0,0,0,0]
当 i=1 时,由于 74 大于 73,因此移除栈顶元素 0,赋值 ans[0]:=1-0,将 1 进栈。
- stack=[1(74)]
- ans=[1,0,0,0,0,0,0,0]
当 i=2 时,由于 75 大于 74,因此移除栈顶元素 1,赋值 ans[1]:=2-1,将 2 进栈。
- stack=[2(75)]
- ans=[1,1,0,0,0,0,0,0]
当 i=3 时,由于 71 小于 75,因此将 3 进栈。
- stack=[2(75),3(71)]
- ans=[1,1,0,0,0,0,0,0]
当 i=4 时,由于 69 小于 71,因此将 4 进栈。
- stack=[2(75),3(71),4(69)]
- ans=[1,1,0,0,0,0,0,0]
当 i=5 时,由于 72 大于 69 和 71,因此依次移除栈顶元素 4 和 3,赋值 ans[4]:=5-4 和 ans[3]:=5-3,将 5 进栈。
- stack=[2(75),5(72)]
- ans=[1,1,0,2,1,0,0,0]
当 i=6 时,由于 76 大于 72 和 75,因此依次移除栈顶元素 5 和 2,赋值 ans[5]:=6-5 和 ans[2]:=6-2,将 6 进栈。
- stack=[6(76)]
- ans=[1,1,4,2,1,1,0,0]
当 i=7 时,由于 73 小于 76,因此将 7 进栈。
- stack=[6(76),7(73)]
- ans=[1,1,4,2,1,1,0,0]
/**
* @param {number[]} temperatures
* @return {number[]}
*/
var dailyTemperatures = function(temperatures) {
let stack = []
// 根据题目要求如果之后气温不再升高
// 该位置用0代替,因此默认值设置为0
let res = Array(temperatures.length).fill(0)
for (let i = 0; i < temperatures.length; i++) {
// 栈不为空且当前索引对应的温度大于栈顶索引对应的温度
// 说明当前索引对应的温度是比栈顶索引对应的温度更高
// while循环表示:
// 当前索引对应的温度比栈中已存索引对应温度高时,则栈顶元素出栈
while (stack.length && temperatures[i] > temperatures[stack[stack.length - 1]]) {
// 栈顶索引出栈后栈的新的大小
let len = stack.length
// 前索引对应的温度大于栈顶索引对应的温度
if (temperatures[i] > temperatures[stack[len - 1]]) {
// 当前索引与栈顶索引的差值表示的就是需要等待的天数
res[stack[len - 1]] = i - stack[len - 1]
// 栈顶索引出栈
stack.pop()
}
}
// 将当前考察温度的索引入栈,看后面是否有比其高的温度
stack.push(i)
}
return res
};
借鉴: https://leetcode-cn.com/problems/daily-temperatures/solution/leetcode-tu-jie-739mei-ri-wen-du-by-misterbooo/ https://leetcode-cn.com/problems/daily-temperatures/solution/mei-ri-wen-du-by-leetcode-solution/