42. 接雨水
文字讲解:代码随想录
视频讲解:单调栈,经典来袭!LeetCode:42.接雨水_哔哩哔哩_bilibili
解题思路
思路一:单调栈
我们要找到矩形作为底时,左边和右边第一个比它大的元素
1.使用单调栈内元素的顺序
应该是从栈头到栈底,是从小到大的,因为一旦发现更大的了,就出现凹槽了,栈头左边第二个元素就是凹槽左边的柱子,而添加的元素就是凹槽右边的柱子
2.模拟过程
h[i] < h[st.top()] 直接加入到栈中
h[i] == h[st.top()] 弹出和直接加入都可,结果是一样的,只是计算过程不同,我们先按加入来算
h[i] > h[st.top()] 此时就发现凹槽了
mid = st.top() 先存柱子底的下标,然后弹出,才能取左边的凹槽
st.pop()
h = min(st.top(),h[i]) - h[mid] 这一行雨水的高度
w = i - st.top() - 1; 这一行雨水的宽度
s+=h*w
然后重复处理,按照我们这种计算结果,那么遇到相同的情况,计算结果就为0,不影响结果
class Solution {
public:
int trap(vector<int>& height) {
stack<int> st;
int sum = 0;
st.push(0); //第一个元素入栈
for(int i = 1 ;i < height.size(); i++)
{
if(height[i]<height[st.top()] || height[i]==height[st.top()])
st.push(i);
else
{
while(!st.empty() && height[i]>height[st.top()])
{
int mid = st.top();
st.pop();
if(!st.empty()) //因为有pop操作,还需要判断是否为空栈
{
int h = min(height[i],height[st.top()]) - height[mid];
int w = i - st.top() - 1;
sum+=h*w;
}
}
st.push(i);
}
}
return sum;
}
};
84.柱状图中最大的矩形
文字讲解:代码随想录
视频讲解:单调栈,又一次经典来袭! LeetCode:84.柱状图中最大的矩形_哔哩哔哩_bilibili
解题思路
1.基础思路
假设我们遍历到6,左边和右边都比它小,无法扩展,因此面积为6*1
遍历的是5,左边是1,比它小,无法扩展,右边是6,比它大,可以扩展,面积为5*2
因此,我们只需要找左和右边第一个比它小的,这样就可以找到宽,高就是当前这个柱子
2.单调栈顺序
因为要找的是第一个比它小的,因此从栈顶到栈底是从大到小的,递减的
3.模拟过程
当遇到第一个小与栈口元素时
mid = st.top();
左边比它小的一定是遍历过的元素,也就是栈口元素旁边的元素
st.pop();
left = st.top();
right = i;
h = height[mid]
w = right - left -1 求的是中间的宽度
4.细节处理,首尾加0
如果数组本身就是升序的,例如[2,4,6,8],那么入栈之后 都是单调递减,一直都没有走 情况三 计算结果的哪一步,所以最后输出的就是0了。 如图:
因此,尾部要加0
如果数组本身是降序的,例如 [8,6,4,2],在 8 入栈后,6 开始与8 进行比较,此时我们得到 mid(8),rigt(6),但是得不到 left,因为空栈我们不做处理,因此就跳过了
因此头部要加0
class Solution {
public:
int largestRectangleArea(vector<int>& heights) {
stack<int> st; //用栈来记录遍历过的元素
heights.insert(heights.begin(),0);
heights.push_back(0);
st.push(0);
int result = 0;
for(int i = 1 ; i<heights.size();i++)
{
if(heights[i]>heights[st.top()])
st.push(i);
else if(heights[i]==heights[st.top()])
{
st.pop();
st.push(i);
}
else
{
while(!st.empty() && heights[i]< heights[st.top()])
{
int mid = st.top();
st.pop();
if(!st.empty())
{
int left = st.top();
int right = i;
int h = heights[mid];
int w = right - left - 1;
result = max(result,h*w);
}
}
st.push(i);
}
}
return result;
}
};