84. 柱状图中最大的矩形
目录:
题目
给定 n个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。
求在该柱状图中,能够勾勒出来的矩形的最大面积。
示例 1:
输入:heights = [2,1,5,6,2,3]
输出:10
解释:最大的矩形为图中红色区域,面积为 10
示例 2:
输入: heights = [2,4]
输出: 4
提示:
1 <= heights.length <=10^5
0 <= heights[i] <= 10^4
暴力法
- 我们可以遍历每根柱子,以当前柱子 i 的高度作为矩形的高,
- 那么矩形的宽度边界即为向左找到第一个高度小于当前柱体 i 的柱体,向右找到第一个高度小于当前柱体 i 的柱体。
- 对于每个柱子我们都如上计算一遍以当前柱子作为高的矩形面积,最终比较出最大的矩形面积即可。
class Solution { public int largestRectangleArea(int[] heights) { int n = heights.length; if(n==0)return 0; int ret = 0; for(int i = 0;i<n;i++) { int width = 1; int left = i-1; while(left>=0 && heights[left]>=heights[i]) { width++; left--; } int right = i+1; while(right<n && heights[right]>=heights[i]) { width++; right++; } if(width*heights[i]>ret)ret = width*heights[i]; } return ret; } }
单调栈法
- 本质还是枚举以每一个柱体i的高度为矩形的高,向左、向右所能构成的最大的矩形宽度
- 暴力法寻找左边界需要$o(N)$,而借助于非递减单调栈,对于栈中的每一个元素,它的左边界是它的栈中的下一个元素
因此做法就很简单了,
- 我们遍历每个柱体,若当前的柱体高度大于等于栈顶柱体的高度,说明栈顶柱体还没有达到右边界,就直接将当前柱体入栈,
- 否则若当前的柱体高度小于栈顶柱体的高度,说明当前栈顶柱体找到了右边的第一个小于自身的柱体,那么就可以将栈顶柱体出栈来计算以其为高的矩形的面积了。
最后若栈中还有元素,则根据我们的过程,
- 栈中每个元素的左边界为它在栈中的下一个柱体,
- 由于这个元素还在栈中,所以它的右边界还没找到才仍然留在了栈中(若找到了就出栈了),留在栈中的都是右边界还没有找到的,所以计算以它为高度的最大矩形时,最右边界是n,
- 所有不在栈中的元素都是已经被消掉的,因为它的左右边界都是已经找到的了,已经是确定的了,已经没有利用价值了,所以才被消掉
class Solution { public int largestRectangleArea(int[] heights) { Deque<Integer> stk = new ArrayDeque<>(); int area = 0,n = heights.length; for(int i = 0; i < n; ++i) { while(!stk.isEmpty() && heights[i] < heights[stk.peek()]) { int h = heights[stk.peek()]; stk.pop(); int w = stk.isEmpty() ? i : i-1-stk.peek(); area = Math.max(h * w, area); } stk.push(i); } while(!stk.isEmpty()) { int h = heights[stk.peek()]; stk.pop(); int w = stk.isEmpty() ? n : n-1-stk.peek(); area = Math.max(h * w, area); } return area; } }