单调栈相对于栈的区别在于单调栈中的元素具有单调性,或单调递增,或单调递减。下面分享一道关于单调栈的题。
每日温度
给定一个整数数组 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]
class Solution {
public int[] dailyTemperatures(int[] temperatures) {
Deque<Integer> stack = new ArrayDeque<>();
int ans[] = new int[temperatures.length];
for(int i = 0;i < temperatures.length;i++){
if(stack.isEmpty() || temperatures[stack.peek()] >= temperatures[i]){
stack.push(i);
}else{
while(!stack.isEmpty() && temperatures[stack.peek()] < temperatures[i]){
int idx = stack.pop();
ans[idx] = i - idx;
}
stack.push(i);
}
}
return ans;
}
}
以[73,74,75,71,69,72,76,73]为例子,说明上述代码的执行过程。首先定义一个栈和一个ans的数组,ans数组用于保存最终的结果,ans数组中下标i表示第i天,ans[i]表示ans[i]天之后,气温比第i天的气温更高。ans初始值为[0, 0, 0, 0, 0, 0, 0, 0]。
进入for循环,遍历temperatures数组的第一个元素73,由于stack为空,将元素73对应的下标i放入stack中,stack为[0],对应的值为[73]。之后遍历第二个元素74,显然74温度高于73,进入else,之后是while循环,将栈中所有比74小的温度对应的下标弹出,stack中仅有温度73,将73弹出,ans[0] = 1 - 0,1为74对应下标,也就是i,stack.peek()就是栈顶元素下标,就是73在temperatures中的下标,就是0。这样就得到第0天温度73,之后的一天温度比当天温度高。最后将74对应的下标压入栈中,stack为[1],对应的为[74]。
遍历元素75,同理,温度75比栈顶元素74温度要高,得到ans[1] = 1。将栈顶元素74下标弹出,压入温度75对应的下标2,stack为[2],对应的值为[75]。之后遍历元素71,71小于栈顶元素75,将温度71下标压入栈中,得到stack为[3, 2],对应的值为[71, 75],继续遍历元素69,小于栈顶元素71,将69对应的元素下标加入栈中,得到stack为[4, 3, 2],对应的值为[69, 71, 75]。继续遍历元素72,72大于栈顶元素,进入else中,while循环将栈中所有小于72的元素弹出,69弹出,ans[4] = 5 - 4 = 1,说明第4天的温度69,第二天的温度超过69,为72。之后是71弹出,ans[3] = 5 - 3 = 2,说明第三天的温度为71,两天之后温度会超过71,为72。之后将温度72的下标压入栈中,stack为[5, 2]对应的值为[72, 75]。之后遍历元素76,同理76大于栈顶元素72,进入else,while循环将栈中所有小于76的元素弹出,得到ans[5] = 6 - 5 = 1,ans[2] = 6 - 2 = 4。将76对应下标压入栈中,stack为[6],对应的值为[76],最后遍历元素73,73小于栈顶元素76,将73对应下标压入栈中,此时stack为[7, 6],对应的值为[73, 76]。外层for循环结束,最后ans为[1, 1, 4, 2, 1, 1, 0, 0]。
可以明显地观察到上述stack中栈存放的下标对应的温度始终都是升序的,这就是单调栈。