题目:
给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。
求在该柱状图中,能够勾勒出来的矩形的最大面积。
思路:
- 首先可以想到暴力法,遍历一遍高度数组
heights[]
,每次遍历一个矩形位置,就对他的左右两边界进行判断,如果左边或右边高度大于等于当前位置,就也可以包括进来,求出面积并和最大面积做对比进行更新。 - 暴力法的时间复杂度为O(n²),我们可以通过空间换时间的角度来降低时间复杂度为O(n)
- 我们可以设置一个栈空间来保存每一个位置的索引,因为高度可以通过数组得出,我们只需要知道宽度,就能求出面积。
以下为代码+注释:
public int largestRectangleArea(int[] heights) {
int len = heights.length;
if(len == 0){
return 0;
}
if(len == 1){
return heights[0];
}
int maxRes = 0;
// 创建一个栈结构,存放矩形的索引
Deque<Integer> stack = new ArrayDeque<>();
// 依次遍历每一个矩形
// 每次都将该索引加入到栈末尾,如果碰到当前位置的高度比前面的小,那么就要对前一个位置的最大面积进行计算了,怎么计算?首先看要计算面积的矩形位置前面还有没有和它高度相同的,有就一并弹出
for(int i = 0; i < len; i++){
// 碰到当前位置高度比前面低了,那么一定能求出来前面高的矩形的面积,因为到这里距离变低,就截断了
while(!stack.isEmpty() && heights[i] < heights[stack.peekLast()]){
int curWidth = 0;
// 首先将要求面积的矩形从栈中弹出
int curHeight = heights[stack.pollLast()];
// 如果前面有高度和当前高度相同的矩形 ,也一起弹出
while(!stack.isEmpty() && curHeight == heights[stack.peekLast()]){
stack.pollLast();
}
if(stack.isEmpty()){
curWidth = i;
}else{
// 因为计算的是中间的宽度,因此要-1,不带左右两边边界
curWidth = i - stack.peekLast() - 1;
}
maxRes = Math.max(maxRes, curWidth * curHeight);
}
// 最后不要忘记将当前位置的索引入栈
stack.addLast(i);
}
// 将整个数组遍历一遍之后,如果栈中还有值,说明还有面积没有计算
while(!stack.isEmpty()){
int curWidth = 0;
// 从后向前依次弹出计算
int curHeight = heights[stack.pollLast()];
// 如果前面还有和当前矩形高度相同的,那么一并弹出
while(!stack.isEmpty() && curHeight == heights[stack.peekLast()]){
stack.pollLast();
}
// 这里因为右边已经没有数据了,就把右边界设置为len,也就是假设数组len索引处有一个长度为0的矩形
if(stack.isEmpty()){
curWidth = len;
}else{
curWidth = len - stack.peekLast() - 1;
}
maxRes = Math.max(maxRes, curWidth * curHeight);
}
return maxRes;
}
笔者也在不断学习,如有错误,欢迎指正!