单调栈是一种思想,是用来维护某种限制下的最大最小值,通常只是维护一个最大值或者最小值,不能为了用单调栈而用. -----------无名氏
最简单的思想当然是直接从每一个i开始往后寻找下一个更大的元素,但是这种思想是O(n^2),对1e5的数据会超时
我们使用单调栈优化,也就是用单调栈这种数据结构保存当前的最大值
我们介绍两种使用单调栈遍历的方法,来深化理解,一种从左往右,一种从右往左
法一: 从左往右
我们从左往右遍历数组
每当遇到更大的元素,就把先前小于等于它的元素弹出去,再把它加进来,而当我们遇到一个更小的元素的时候,就把它直接加入就行
显然单调栈是递减的,而我们pop移除的元素就是发现它的下一个更大值temperatures[i],当结束时还存在在栈里的元素就都应该是0
参考代码如下:
class Solution {
public:
vector<int> dailyTemperatures(vector<int>& temperatures) {
stack<int> stk;
vector<int> ans(temperatures.size(),0);
int count=0;
for(int i=0;i<temperatures.size();i++){
while(!stk.empty() && temperatures[i]>temperatures[stk.top()]){
ans[stk.top()]=i-stk.top();
stk.pop();
}
stk.push(i);
}
return ans;
}
};
法二: 从右往左
从右往左的方法更符合我们的单调栈的及时删除无用元素的思想
我们从右往左遍历,当出现一个更大的元素temperatures[i]时,那些temperatures[j] 满足 i<j,temperatures[i]>=temperatures[j]都不会是之后遍历中第一个更大值了,因为一定会被当前的temperatures[i]取代,所以我们可以把temperatures[j]删除.
代码实现如下:
class Solution {
public:
//空间复杂度是 O(min(n,U)) U=max-min+1 因为不存在相同元素
vector<int> dailyTemperatures(vector<int>& temperatures) {
int len=temperatures.size();
vector<int> ans(len,0);
stack<int> stk;
for(int i=len-1;i>=0;i--){
while(!stk.empty() && temperatures[i]>=temperatures[stk.top()]){
stk.pop();
}
ans[i]=stk.empty()?0:stk.top()-i;
stk.push(i);
}
//感觉单调栈的题目很多是使用的下标存储在stack里面的 这样其实多了一个可以存取的属性
return ans;
}
};
note:
从这个题目我们也可以略见一斑,
1.一般的单调栈,单调队列的题目是有两种取值的时候,一种是弹出的时候,这个时候是它刚不满足限制的时候,另一种就是移除无用元素之后,使得当前的栈顶 / 队头 就是当前维护的 最大/最小 值的时候.
2.单调栈 / 单调队列很多是存储的数组元素的下标, 因为这样其实是多了一个属性