代码随想录算法训练营四十二天|单调栈part02
LeetCode 42 接雨水
题目链接:42. 接雨水 - 力扣(LeetCode)
给定 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;所以体积就是:高度*宽度。
根据以上处理逻辑,给出代码:
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
依然要明确单调栈内元素的顺序:
从栈顶到栈底的顺序应该是从大到小的顺序。因为本题是要找到每个柱子左右两边第一个小于该柱子的柱子,和接雨水正好是相反的。
除了顺序,其他的逻辑和接雨水是差不多得,这里就不再赘述了。
代码如下:
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。