84.柱状图中最大的矩形
这道题和接雨水那道题是遥相呼应的
因为,接雨水那道题需要找某一列左右两边第一个高于该列的,而本题要找某一列左右两边第一个低于该列的,正好相反。因此我们的单调栈从栈头到栈底应该是从大到小的(从栈头弹出元素)。
此时大家应该可以发现其实就是栈顶和栈顶的下一个元素以及要入栈的三个元素组成了我们要求最大面积的高度和宽度
分3种情况:
1.当前元素大于栈头元素,直接push
2.当前元素等于栈头元素,直接push
3.当前元素小于栈头元素,计算出面积然后再push当前元素
注意在这题中,我们需要在height数组的头部和尾部分别加上数字0;
在头部加上0的目的是为了防止height数组是降序数组的时候如[8,4,3,2]
在尾部加上0的目的是为了防止height数组是升序数组的时候如[2,3,4,8]
代码实现
在这里我开始不太明白为什么是 int h=newHeights[mid];
后来想明白:每次我们只会弹出一个元素即mid来计算,因此参与面积计算的就是当前遍历到的柱形和被弹出的柱形,所以要以被弹出的柱形的高度作为面积的高,如果满足st非空且当前元素小于栈头元素,那么会一直弹出栈里的元素
class Solution {
public int largestRectangleArea(int[] heights) {
Stack<Integer> st = new Stack<Integer>();
int[] newHeights=new int[heights.length+2];
newHeights[0]=0;
newHeights[newHeights.length-1]=0;
for(int i=0;i<heights.length;i++){
newHeights[i+1]=heights[i];
}
st.push(0);
int result=0;
for(int i=1;i<newHeights.length;i++){
if(newHeights[i]>=newHeights[st.peek()]){//当前元素大于栈头元素,直接push
st.push(i);
}
// else if(newHeights[i]==st.peek()){//当前元素等于栈头元素,直接push
// }
else{//当前元素小于栈头元素,计算出面积然后再push当前元素
while(!st.isEmpty()&&newHeights[i]<newHeights[st.peek()]){
int mid=st.pop();
int left=st.peek();
// int h=Math.min(left,i);//h=Math.min(left,i);还是int h=heights[mid];
int h=newHeights[mid];//注意这里是int h=heights[mid];每次我们只会弹出一个元素即mid来计算,因此参与面积计算的就是当前遍历到的柱形和被弹出的柱形,所以要以被弹出的柱形的高度作为面积的高,如果满足st非空且当前元素小于栈头元素,那么会一直弹出栈里的元素
int w=i-left-1;
result=Math.max(result,w*h);
System.out.println(result);
}
}
st.push(i);//这次计算完当前的最大面积后要将这次到达的下标入栈,方便下一次计算
}
return result;
}
}
接下来先总结回顾再准备二刷时间