[单调栈]牛客网 直方图内最大矩形

题目链接
题目给一个向量,里面存一个序列,表示一个直方图的各个元素高,要求出这个直方图中的最大矩形面积;

构建一个递增的单调栈:
[单调栈就是一个栈,栈底元素向栈头元素递增,新加入的元素如果小于栈顶元素,就把栈顶元素pop,直到栈顶元素小于新加入的元素]
我们使用这样的数据结构 p a i r < i n t , i n t > , first中存储高度height, second中存储宽度width;

对于每一个元素,都先加入到单调栈中,在加入过程中,按以下操作进行:
1.如果该元素大于栈顶元素,直接加入到栈中;
2.如果该元素小于或等于栈顶元素,则把栈顶元素pop出来,同时更新答案=(height*width),要注意对width的修正;
所有元素加入到栈中后,再把栈中元素一一pop出来,每次pop出来的时候都更新答案;

我觉得可以这样理解这个算法:
首先,我们假设,现在已经有了一些直方柱,最大矩形面积已经求出了为ans,然后对于一个新加进入的直方柱,有可能对答案产生影响,有2种可能:
1.新加入的高比前一个矩形大,单个矩形的面积已经超过了前面所求的的ans;
2.新加入的高比前一个矩形小,最大矩形的面积可能是 新加入的矩形的高*这个矩形之前所有比它低的矩形的数量和(即为宽度)

那么我们只需要维护2个数据就可以测试,是否会落入这两种可能:
我们假象,如果要加入的柱子的高高于前面的最后一个柱子,那这个柱子可能会对后面的新加入的柱子能不能改变答案有影响,所以我们要在栈中保留这个数据;
但是如果新加入的柱子的高低于前面的最后一柱子,那前面的柱子的高对于求最大面积而言已经没有用,可以直接pop出来,把之前所存储的宽度+1,存入新加入的柱子中即可;
但是注意在更新答案的时候要把pop出来的元素的宽度加入宽度中,修正答案;

最终代码如下:

class MaxInnerRec {
public:
int countArea(vector<int> A, int n) {
    int ans=0,sun=0;
    pair<int ,int > temp;
    stack<pair<int ,int > > s;
    for(int i=0;i<n;i++){

        while(!s.empty() && s.top().first>=A[i]){
            temp=s.top();s.pop();
            ans=max(ans,temp.first*(temp.second+sun));
//          cerr<<temp.first<<"  "<<temp.second<<"  "<<ans<<endl;
            sun+=temp.second;
        }
        s.push(make_pair(A[i],1+sun));
        sun=0;
    }
    while(!s.empty()){
        temp=s.top();s.pop();
        ans=max(ans,temp.first*temp.second);
//      cerr<<temp.first<<"  "<<temp.second<<"  "<<ans<<endl;
        if(!s.empty()) s.top().second+=temp.second;
    }
    return ans;
}

};

猜你喜欢

转载自blog.csdn.net/qq_33982232/article/details/81670822