class Solution {
public:
int largestRectangleArea(vector<int>& heights) {
//法一:枚举宽,超时
if(0){
int n=heights.size();
int area=0;
for(int left=0;left<n;++left){
int minH=INT_MAX;
for(int right=left;right<n;++right){
minH=min(minH,heights[right]);
area=max(area,(right-left+1)*minH);
}
}
return area;
}else if(0){
//法二:枚举高,超时
//固定矩形的高度h,随后从这个柱子开始向两侧延伸,只到遇到高度小于h的柱子,就确定矩形的左右边界
int n=heights.size();
int area=0;
for(int mid=0;mid<n;++mid){
int h=heights[mid];
int left=mid,right=mid;
while(left-1>=0&&heights[left-1]>=h){
--left;
}
while(right+1<n&&heights[right+1]>=h){
++right;
}
area=max(area,(right-left+1)*h);
}
return area;
}else if(0){
//法三:单调栈,是对枚举高的优化
//求每一根柱子左侧且最近的小于其高度的柱子及右侧且最近的小于其高度的柱子,左右边界
//若0位置大于1位置,则0可不能是2位置的左侧且最近的小于其高度的柱子,明显1位置更符合
//单调栈栈中大于i位置的元素可以出栈
int n=heights.size();
vector<int> left(n),right(n);
stack<int> ls,rs;
for(int i=0;i<n;i++){
while(!ls.empty()&&heights[ls.top()]>=heights[i]){
ls.pop();
}
left[i]=ls.empty()?-1:ls.top();
ls.push(i);
}
for(int i=n-1;i>=0;--i){
while(!rs.empty()&&heights[rs.top()]>=heights[i]){
rs.pop();
}
right[i]=rs.empty()?n:rs.top();
rs.push(i);
}
int ans=0;
for(int i=0;i<n;++i){
ans=max(ans,(right[i]-left[i]-1)*heights[i]);
}
return ans;
}else if(1){
//法四:单调栈+常数优化
int n=heights.size();
//left记录i位置左侧最近的小于其高度的柱子下标
//right记录i位置右侧最近的小于其高度的柱子的下标
//单调栈中记录小于i位置柱子高度的位置下标,若高度大于等于则出栈,栈顶位置为左侧最近的小于i位置的柱子下标
//左、右边界中的柱子均满足大于i位置的柱子高度,计算面积时以i位置柱子高度计算
vector<int> left(n),right(n,n);
stack<int> mono_stack;
for(int i=0;i<n;i++){
while(!mono_stack.empty()&&heights[mono_stack.top()]>=heights[i]){
right[mono_stack.top()]=i;
mono_stack.pop();
}
left[i]=mono_stack.empty()?-1:mono_stack.top();
mono_stack.push(i);
}
int ans=0;
for(int i=0;i<n;++i){
ans=max(ans,(right[i]-left[i]-1)*heights[i]);
}
return ans;
}
}
};