LeetCode 42 接雨水
给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
示例 1:
输入:height = [0,1,0,2,1,0,1,3,2,1,2,1]
输出:6
解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。
示例 2:
输入:height = [4,2,0,3,2,5]
输出:9
首先要明确以下几个问题:
1.单调栈按行方向计算雨水容量,如图:

2.使用单调栈内元素的顺序:
从栈顶到栈底的顺序应该是从小到大的顺序。因为一旦发现添加的柱子的高度大于栈顶元素,说明出现凹槽,栈顶元素就是凹槽底部的柱子,栈顶第二个元素就是凹槽左边的柱子,新添加的柱子就是凹槽右边的柱子。
如图所示:

3.遇到相同高度的柱子怎么办,如图所示:

我们把栈顶元素先弹出,再将新元素加入栈中,因为高度相同,我们只使用最靠右边的柱子来计算即可。
根据以上分析,接下来就看单调栈的处理逻辑:
1.当前加入的元素高度小于栈顶元素的高度,直接将当前元素加入栈中即可;
2.当前加入的元素高度等于栈顶元素的高度,先将栈顶元素弹出,再将当前元素加入栈中即可;
3.当前加入的元素高度大于栈顶元素的高度:首先先将栈顶元素弹出,那么这个柱子就是凹槽的底部,它的高度记为mid;此时栈顶元素就是凹槽左边的柱子,当前加入的元素时凹槽右边的位置;所以雨水的高度 应该是:凹槽两边柱子的最小高度-mid ;宽度 是:凹槽右边的下标-凹槽左边的下标-1;所以体积就是:高度*宽度。
根据以上处理逻辑,给出代码:
java
class Solution {
public int trap(int[] height) {
int n = height.length;
int res = 0;
Stack<Integer> st = new Stack<>();
st.push(0);
for (int i = 1; i < n; i++) {
if (height[i] == height[st.peek()]) {
st.pop();
}
while (!st.isEmpty() && height[i] > height[st.peek()]) {
int mid = height[st.peek()];
st.pop();
if (!st.isEmpty())
res += (Math.min(height[i], height[st.peek()]) - mid) * (i - st.peek() - 1);
}
st.push(i);
}
return res;
}
}
LeetCode 84 柱状图中最大的矩形
题目链接:84. 柱状图中最大的矩形 - 力扣(LeetCode)
给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。
求在该柱状图中,能够勾勒出来的矩形的最大面积。
示例 1:
输入:heights = [2,1,5,6,2,3]
输出:10
解释:最大的矩形为图中红色区域,面积为 10
示例 2:
输入: heights = [2,4]
输出: 4
依然要明确单调栈内元素的顺序:
从栈顶到栈底的顺序应该是从大到小的顺序。因为本题是要找到每个柱子左右两边第一个小于该柱子的柱子,和接雨水正好是相反的。
除了顺序,其他的逻辑和接雨水是差不多得,这里就不再赘述了。
代码如下:
java
class Solution {
public int largestRectangleArea(int[] heights) {
int[] height=new int[heights.length+2];
height[0]=0;
for(int i=1;i<=heights.length;i++){
height[i]=heights[i-1];
}
height[heights.length+1]=0;
int n=height.length;
int res=0;
Stack<Integer> st=new Stack<>();
st.push(0);
for(int i=1;i<n;i++){
if(height[i]==height[st.peek()])st.pop();
while(!st.isEmpty()&&height[i]<height[st.peek()]){
int mid=height[st.peek()];
st.pop();
if(!st.isEmpty()){
int left=st.peek();
int right=i;
res=Math.max(res,mid*(right-left-1));
}
}
st.push(i);
}
return res;
}
}
可以看到,在heights数组首位都加了一个元素0,这是为什么?
首先,在末尾加0是为了防止数组本身就是非递减的,那么这样一直到最后都没有进行res的计算,直接返回0,所以要在末尾加一个0。
其次,在开头加0是为了防止数组本身是非递增的,那么这样对于第一个柱子,我们无法得到left,所以要在开头加一个元素0。