单调栈中存放的数据一般是有序的,所以单调栈也分为单调递增栈和单调递减栈
单调递增栈就是从栈底到栈顶数据是从大到小,单调递减栈就是从栈底到栈顶数据是从小到大。
cpp栈的用法 :
创建栈 stack<类型> 变量名
- push(): 向栈内压入一个成员;
- pop(): 从栈顶弹出一个成员;
- empty(): 如果栈为空返回true,否则返回false;
- top(): 返回栈顶,但不删除成员;
- size(): 返回栈内元素的大小;
力扣84. 柱状图中最大的矩形 - 力扣(LeetCode)
此题构造单调递增栈
class Solution {
public:
int largestRectangleArea(vector<int>& heights) {
heights.push_back(-1);//构造单调递增的栈,往数组最后插入一个非常小的数
stack<int>st;
int ans=0,k=0;
for(int i=0;i<heights.size();i++)
{
if(st.empty()||heights[i]>=heights[st.top()]){
st.push(i);//当数组元素大于等于栈顶元素时将数组下标插入栈中
}
else{
while(!st.empty()&&heights[i]<heights[st.top()])
{
k=st.top();//将栈顶元素的值存储
ans=max(ans,heights[st.top()]*(i-st.top()));//计算图形面积
st.pop();//将栈顶元素弹出
}
st.push(k);//将之前的栈顶元素入栈
heights[k] = heights[i];//把i对应的值赋给栈顶元素
}
}
return ans;
}
};
关于这一部分为什么不能写st .push(i)。
st.push(k);
heights[k] = heights[i];
/*
为什么不能写为
st.push(i);
*/
例如heights=[2,1,2]的情况下,刚开始时2进栈(栈内元素用橙色标明,未进栈的用蓝色)
i和top进行比较
由于i指针指向的值小于top指向的值,根据代码计算ans为2*1=2,同时弹出栈顶元素
假设我们此时的代码是st .push(i),那么就会变成这样,
此时i指针再次后移指向-1,栈中所有元素出栈,ans计算答案得到最大值为1*2为2
但实际上这题的最大值为3 这样的情况才是最大值
当我们用这段代码时 st.push(k);heights[k] = heights[i];将最开始的下标存入栈中,然后把值改为i的值。相当于把比heights[i]大的值用下标的形式存起来了(比heights[i]大的值事实上已经移出栈外,但是通过下标的差值来计算面积时仍然相当于参与了进去)
当i指向-1的位置时,计算ans得到ans=1*3=3,返回ans,就是我们要找的正确答案。
力扣739. 每日温度 - 力扣(LeetCode)
此题为单调递减栈
class Solution {
public:
vector<int> dailyTemperatures(vector<int>& temperatures) {
int n=temperatures.size();
vector<int>res(n,0);//创建一个n个0的数组
stack<int>st;//创建一个栈
for(int i=0;i<n;i++){
while(!st.empty()&&temperatures[i]>temperatures[st.top()]){
//只要温度大于栈顶温度且栈内非空
auto t=st.top();//先将栈顶元素用变量存起来
st.pop();//弹出栈顶元素
res[t]=i-t;//计算第t天到第i天隔的时间
}
st.push(i);//将i入栈
}
return res;//返回答案数组
}
};
当进行到75,71,69入栈后
此时72入栈,72大于69,数组res[4]值修改为5-4=1,69出栈。仍满足while循环继续比较,72大于71,数组res[3]的值修改为5-3=2,71出栈。72小于75,不满足while循环条件,72入栈。运行完毕后返回res数组即为正确答案。