题目这道题目算是比较难的了,需要好好解释一下
给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。
求在该柱状图中,能够勾勒出来的矩形的最大面积。
输出示例
输入: [2,1,5,6,2,3]
输出: 10
代码一(非常好理解,但是时间复杂度非常大,不使用)
class Solution {
public static int largestRectangleArea(int[] heights) {
if (heights.length == 0) {
return 0;
}
if (heights.length == 1) {
return heights[0];
}
//代码的思路非常简单,建立两个数组,nums1和num2;
//nums1用于保存当前位置i左边第一个小于heights[i]的位置加一,也就是左边最后一个不小于heights[i]的数;
//nums2用于保存当前位置i右边第一个小于heights[i]的位置加一;
//例如对于上面的输入,当i等于1时,heights[i]=1,所以nums1[i]=0,这里保存的是对应的位置,也就是heights[0]=2;nums2[i]=2,也就是heights[2]=5;
int[] nums1=new int[heights.length];
int[]nums2=new int[heights.length];
int result=0;
for(int i=0;i<heights.length;i++){
int left=i-1;
int right=i+1;
while(left>=0&&heights[left]>=heights[i]){
left--;
}
while(right< heights.length&&heights[right]>=heights[i]){
right++;
}
nums1[i]=left+1;
nums2[i]=right-1;
}
//接下来我们遍历数组,以每一次遍历的heights[i]为高,向左向右取矩形的长,相乘即可
for(int i=0;i<heights.length;i++){
result=Math.max(result,heights[i]*(nums2[i]-nums1[i]+1));
}
return result;
}
}
代码二,上面的代码是极其不推荐的,接下来我们说另一种常规方式,单调栈实现
class Solution {
public int largestRectangleArea(int[] heights) {
if(heights.length==0){return 0;}
//创建一个栈,要时刻保证栈中的元素是单调递增的,栈中保存的是heights中元素对应的下标位置,注意这点。
Stack<Integer>stack=new Stack<>();
int result=0;
//将栈中存入一个标志位,一会会解释作用
stack.push(-1);
for(int i=0;i<heights.length;i++){
//如果当前栈不为空,要注意这里以栈顶是否为-1,判断是否存在元素;
//且heights[i]小于栈顶元素(前面也说了,要时刻保证栈为单调栈);
//就需要将栈顶元素拿出,并以栈顶元素在heights中的大小为宽
//接着我们需要求矩阵对应的长,注意一点矩阵的长并不是单纯的用i去减去弹出栈的元素(栈中保存的是元素在heights中的位置);
//而是先将栈顶元素弹出,宽等于i减去弹出后的栈的栈顶元素再减一
//例如heights={3,6,7,5,4};
//对于前三个元素直接插入栈中,当i等于3,heigths[i]=5时不满足单调递增
//所以弹出栈中的元素,对于7来说,实际上我们是求以7为宽,且以i等于2这个位置为右边界向左去求对应矩阵的面积;
//此时将7弹出后,栈顶元素为1(栈中保存的是元素对于在heights的位置),因此长就等于i-stack.peek()-1等于1,这么看确实也等于用i减去原来的栈顶元素(减去7的位置),但是这是在连续递增的前提下才满足的
//同理6也是这样弹出
//例如当插入4时,此时栈中元素从顶向下依次为3,0,-1(注意是元素在heights的位置);
//由于4是小于5的所以我们将栈顶元素弹出,这个时候对应的长度就不在等于单纯的用i减去弹出的元素,
//因为虽然之前的6和7都弹出了,但是5是小于6和7的,
//所以我们以5为宽的矩阵真正的长度应该是从6这个位置一直到5这个位置也就是三。
while(stack.peek()!=-1&&heights[stack.peek()]>heights[i]){
result=Math.max(result,heights[stack.pop()]*(i-stack.peek()-1));
}
stack.push(i);
}
//最后栈中若不为空的话,我们还要继续进行判断
while(stack.peek()!=-1){
result=Math.max(result,heights[stack.pop()]*(heights.length-stack.peek()-1));
}
return result;
}
}