本文主要介绍单调栈解法和单调栈的相关知识。
单调栈
什么是单调栈?
单调栈是存放数据有序的栈,单调栈也分为单调递增栈和单调递减栈: 单调递增栈:栈底大,栈顶小 单调递减栈:栈底小,栈顶大 对于单调栈题目来说,简单的只需要维护一个单调递增/递减栈即可,当破坏这个规律的时候,进行计算即可。
相比于单调队列、优先队列来说,单调栈是一种解决特殊问题的方法。不过也可以用来解决Dp优化等问题。
攒青豆
题目介绍
现有 n 个宽度为 1 的柱子,给出 n 个非负整数依次表示柱子的高度,排列后如下图所示,此时均匀从上空向下撒青豆,计算按此排列的柱子能接住多少青豆。(不考虑边角堆积)
测试用例
以下为上图例子的解析:
输入:height = [5,0,2,1,4,0,1,0,3]
输出:17
解析:上面是由数组 [5,0,2,1,4,0,1,0,3] 表示的柱子高度,在这种情况下,可以接 17 个单位的青豆。
解析
本题是leetcode接雨水题目相同题目。我们通过单调栈来解决。 这个题有两种思路,双指针和单调栈,其区别是双指针按横向接雨水,单调栈按纵向接雨水。我们主要分析单调栈思路。 遍历height数组,我们可以发现,寻找左边第一个比目前数值大的和右边第一个比目前数值大的,形成了一个凹处,就能接到雨水。必须严格大于,否则接不到雨水。即是一个严格的单调递减栈。
代码
class Solution{
public:
int trap(vector<int>& height)
{
stack<int> st;
long long res=0;
for(int i=0;i<height.size();++i)
{
while(!st.empty()&&height[i]>height[st.top]) //出栈计算
{
int top=st.top();
st.pop();
if(st.empty()) break;
int left=st.top();
int currWidth=i-left-1;
int curHeight=min(height[left],height[i])-height[top];
res+=currWidth*curHeight;
}
st.push(i);
}
return res;
}
}
拓展——柱状图中的最大矩形
题目介绍
给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。
求在该柱状图中,能够勾勒出来的矩形的最大面积。
测试用例
输入:heights = [2,1,5,6,2,3]
输出:10
解释:最大的矩形为图中红色区域,面积为 10
解析
用单调栈思路很容易解决。我们要知道,影响这个index处的最大矩形的是前面第一个小于等于自己的元素和后面第一个小于等于自己的元素。
记录最大值为max,我们遍历元素,如上:2,1,5,6,2,3
当我们遍历0(index)时,此时value为2,前面没有比自己小的元素,于是不会影响,后面继续遍历,第一个小于自己的元素就是1,所以我们入栈要进行判断,如果是大于栈顶元素,那么继续找后面第一个小于自己的元素。
于是我们去维护一个单调递增栈:
当我们一看到比栈顶元素小的时候,即破坏单调性的时候,我们就进行出栈计算。
代码
class Solution {
public:
int largestRectangleArea(vector<int>& heights) {
stack<int> st; //来存放目前的索引。
int res=0;
int n=heights.size();
st.push(-1);
for(int i=0;i<n;i++)
{
while(st.top()!=-1&&heights[i]<=heights[st.top()]) //出栈计算
{
int height=heights[st.top()];
st.pop();
int width=i-st.top()-1;
res=max(res,width*height);
}
st.push(i); //入栈
}
while(st.top()!=-1)
{
int height=heights[st.top()];
st.pop();
int width=heights.size()-st.top()-1;
res=max(res,width*height);
}
return res;
}
};