84.柱状图中最大的矩形
思路1:动态规划
1. 本题需要记录每个柱子左边第一个小于该柱子的下标,而不是左边第一个小于该柱子的高度,所以需要循环查找。因此,寻找过程中使用while。
2. 整体思路参考42.接雨水
class Solution {
public int largestRectangleArea(int[] heights) {
int len = heights.length;
int[] minLeftIndex = new int[len];
int[] minRightIndex = new int[len];
minLeftIndex[0] = -1;
for(int i=1;i<len;i++){
int t = i-1;
while(t>=0 && heights[t]>=heights[i]) t = minLeftIndex[t];
minLeftIndex[i] = t;
}
//记录每个柱子右边第一个小于该柱子的下标
minRightIndex[len-1] = len;
for(int i = len-1;i>=0;i--){
int t = i+1;
while(t<len && heights[t]>=heights[i]) t=minRightIndex[t];
minRightIndex[i]=t;
}
int res = 0;
for(int i=0;i<len;i++){
int sum = heights[i]*(minRightIndex[i]-minLeftIndex[i]-1);
res = Math.max(sum,res);
}
return res;
}
}
思路3:单调栈
1. 找每个柱子左右两边第一个小于该柱子的柱子,因此从栈头(元素从栈头弹出)到栈底的顺序应该是从大到小的顺序;栈顶元素,栈顶的下一个元素,以及要入栈的元素一起组成了要求的最大面积的高度和宽度;
2. 分析清楚如下三种情况:
(1)当前遍历的元素heights[i]小于栈顶元素heights[st.top()]:进行操作;
(2)当前遍历的元素heights[i]等于栈顶元素heights[st.top()]:先抛出栈顶元素,再入栈当前所遍历的元素;(也可以不抛出栈顶元素)
(3)当前遍历的元素heights[i]大于栈顶元素heights[st.top()]:直接入栈;
class Solution {
public int largestRectangleArea(int[] heights) {
Stack<Integer> st = new Stack<>();
int[] newHeights = new int[heights.length+2];
newHeights[0]=0;
newHeights[newHeights.length-1]=0;
for(int index = 0;index<heights.length;index++){
newHeights[index+1] = heights[index];
}
heights = newHeights;
st.push(0);
int res = 0;
for(int i=1;i<heights.length;i++){
if(heights[i]>heights[st.peek()]){
st.push(i);
}else if(heights[i]==heights[st.peek()]){
st.pop();
st.push(i);
}else{
while(heights[i]<heights[st.peek()]){
int mid = st.peek();
st.pop();
int left = st.peek();
int right = i;
int w = right-left-1;
int h = heights[mid];
res = Math.max(res,w*h);
}
st.push(i);
}
}
return res;
}
}