题目与题解
84.柱状图中最大的矩形
题目链接: 84.柱状图中最大的矩形
代码随想录题解: 84.柱状图中最大的矩形
视频讲解:单调栈,又一次经典来袭! LeetCode:84.柱状图中最大的矩形_哔哩哔哩_bilibili
解题思路:
看答案,不为难自己
看完代码随想录之后的想法
重点还是怎么将应用题翻译成数学题,才能选择合适的做法。
要求最大的矩形,其实就是以某一个最低高度为矩形的高,将其周围不小于它的高度的柱子宽度加在一起,作为矩形的宽。这样翻译过来,就是要求每一个高度左边和右边第一个高度小于它的下标,这样,左右下标之间的柱子就是矩形的宽度。
与接雨水的题稍微有点反过来,略复杂了一些。
1. 双指针法
遍历两遍heights,分别计算其每个下标左边第一个高度小于它的下标minLeftIndex和每个下标右边第一个高度小于它的下标minRightIndex。为了提高计算效率,以计算左边下标为例,不需要逐一遍历其左边的所有数字中直到找到第一个下标,如果其左边某一个下标高度高于它,那直接取t = minLeftIndex[t]为当前最小下标即可,直到t < 0。为了防止死循环,minLeftIndex[0]初始化要赋值为-1。右边同理。
求完这两个数组后,遍历0-size-1,求出每一个下标对应的最大矩阵大小为minRightIndex[i] - minLeftIndex[i]-1)*heights[i],最后取最大值即可。
class Solution {public int largestRectangleArea(int[] heights) {// 双指针int size = heights.length;int[] minLeftIndex = new int[size];minLeftIndex[0] = -1;for (int i = 1; i < size; i++) {int t = i-1;while (t >= 0 && heights[t] >= heights[i]) t = minLeftIndex[t];minLeftIndex[i] = t;}int[] minRightIndex = new int[size];minRightIndex[size-1] = size;for (int i = size - 2; i >= 0; i--) {int t = i+1;while (t < size && heights[t] >= heights[i]) t = minRightIndex[t];minRightIndex[i] = t;}int res = heights[0];for (int i = 0; i < size; i++) {res = Math.max(res, (minRightIndex[i] - minLeftIndex[i]-1)*heights[i]);}return res;}
}
2. 单调栈
这次的单调栈要变成栈底到栈顶从小到大排列的顺序了,因为要求的是更高的高度对应矩阵的面积。
这样跟接雨水也很类似,如果当前height[i]大于height[s.peek()]直接入栈,如果相等就弹出一个再入栈一个,否则当栈不为空且height[i]小于height[s.peek()]时,循环计算当前矩形的高度mid = height[s.peek()]并弹出栈顶,如果此时栈不为空,就可以获得其左边第一个比它小的高度的下标s.peek()和右边第一个比它小的高度i,得到矩形宽为 i - s.peek() - 1,求得其面积。最后比较得到最大面积即可。
这里需要注意,heights不能直接使用,要先在其前后加两个值0,生成新的矩阵。否则当当前数组是单调的时候,是无法进入计算其面积的循环里面的。
class Solution {public int largestRectangleArea(int[] heights) {// 单调栈Stack<Integer> s = new Stack<>();int[] newHeight = new int[heights.length+2];System.arraycopy(heights, 0, newHeight, 1, heights.length);s.push(0);int res = 0;for (int i = 1; i < newHeight.length; i++) {if (newHeight[i] > newHeight[s.peek()]) {s.push(i);} else if (newHeight[i] == newHeight[s.peek()]){s.pop();s.push(i);} else {while (!s.isEmpty() && newHeight[i] < newHeight[s.peek()]) {int mid = s.pop();if (!s.isEmpty()) {int w = i - s.peek() - 1;res = Math.max(res, w * newHeight[mid]);}}s.push(i);}}return res;}
}
遇到的困难
应用题还是得知道怎么翻译。
单调栈的细节也很多,容易写错。
今日收获
最后一题单调栈,还是有点云里雾里,得再练。
收工了!