Problem
Solution
题意为:给你一个数组,这个数组代表了一个柱状图(数组中的每个元素代表每个柱子的高度),让你求出这个柱状图中能取到的面积最大的矩形面积。
单调栈:栈中元素保持单调递增或递减的单调性。其中栈的单调性是指元素出栈后的序列的单调性,因此栈顶元素大于栈底元素的单调栈是递减栈,反之是递增栈。
这题可以用递减栈来做
顺序遍历原序列:
如果栈为空或栈顶元素对应的数组元素小于等于目前遍历到的元素,则把当前元素的下标入栈
否则,最大的面积就可能出现在之前的元素中(可以这么想,如果元素一直在递增或者不变,那么就相当于高就等于第一个元素不变,但矩形的底一直在增大,因此矩形面积也在增大;反之碰到了变小的元素,虽然底增大了,但是高可能变小了,因此面积变化的趋势是不一定的,因此要重新开始整理栈中的元素)
因为栈中元素是递增的,因此我们每次计算子矩形的面积 (i-top)*heights[top](对于下标为栈顶元素的柱子,他一定能完全向右扩展)
最后就是两点细节:
代码第4行,最后添加一个-1元素,那么我们在碰到-1时,一定能把前面的元素全部出栈,计算完所有可能性
代码19、20行,虽然碰到变小元素需要把大于当前元素全部出栈,但想一下,出栈的下标对应的元素都比当前元素大,因此当前元素也同样可以向左扩展,举例[2,1,2],碰到1比2小,把下标0出栈后,如果入栈了下标1,那么就会出问题。因为下标0元素2,下标为1的1可以向左扩展到下标0,底变长了但高度受限于1,只能取到1。因此我们就把一轮整理中最后出栈的元素对应的元素替换成当前元素,再把最后出栈的下标入栈,这样,我们就把当前元素向左扩展的问题解决了(把下标扩展到了能扩展到的最左边,也就是把矩形的底最大化了)
class Solution {
public:
int largestRectangleArea(vector<int>& heights) {
heights.push_back(-1);
int n=heights.size();
stack<int> st;
int ans=0;
for(int i=0;i<n;++i){
if(st.empty()||heights[i]>=heights[st.top()]){
st.push(i);
}else{
int top;
while(!st.empty()&&heights[st.top()]>heights[i]){
top=st.top();
int t=(i-top)*heights[top];
ans=t>ans?t:ans;
st.pop();
}
st.push(top);
heights[top]=heights[i];
}
}
return ans;
}
};