b_51_面积最大的矩形=柱状图 & 好子数组的最大值(暴力 / 单调栈优化)

面积最大的矩形(柱状图)

有一个正整数的数组(数组值为柱子的高度),化为直方图,求此直方图包含的最大矩形面积。

暴力

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=5e5+5;
ll n,a[N];
int main() {
    std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    cin>>n; for (int i=0; i<n; i++) cin>>a[i];
    ll ans=0;
    for (int i=1; i<n-1; i++) {
        ll l, r;
        for (l=i-1; l>=0; l--)if (a[l]<a[i]) break; //在左边找第一个小于a[i]的
        for (r=i+1; r<n; r++) if (a[r]<a[i]) break; //在右边找第一个小于a[i]的
        ans=max(ans, (r-l-1)*a[i]);    
    }
    cout<<ans;
    return 0;
}

暴力法中我发现需要在每一个位置i的左&右找第一个小于当前元素a[i]的位置,这一步可以用单调栈预处理,栈顶则存的是当前位置左/右边第一个小于自己的位置

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=5e5+5;
ll n,h[N],l[N],r[N];
int main() {
    std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    ll ans=0; stack<int> st;
    cin>>n; for (int i=1; i<=n; i++) cin>>h[i];
    h[0]=-1, st.push(0);           //添加一个0后最左边的柱子就可以有底部长度为1(自己本身)
    for (int i=1; i<=n; i++) {
        while (!st.empty() && h[st.top()]>=h[i]) st.pop();
        l[i]=i-st.top();
        st.push(i);
    }   
    st=stack<int>(), st.push(n+1); //添加一个n+1后最右边的柱子就可以有底部长度为1(自己本身)
    for (int i=n; i>=1; i--) {
        while (!st.empty() && h[st.top()]>=h[i]) st.pop();
        r[i]=st.top()-i;
        st.push(i);
    }   
    for (int i=1; i<=n; i++) ans=max(ans, h[i]*(l[i]+r[i]-1));
    cout<<ans;
    return 0;
}

好子数组的最大分数

子数组 (i, j) 的 分数 定义为 min(nums[i], nums[i+1], ..., nums[j]) * (j - i + 1) 。一个 好 子数组的两个端点下标需要满足 i <= k <= j 。请你返回 好 子数组的最大可能 分数 。

思路:单调栈O(n)求出lmin、rmin(左、右边第一个比自己小的位置),加个判断条件即可

class Solution {
public:
    int maximumScore(vector<int>& A, int k) {
        int n=A.size();
        A.insert(A.begin(), 0), A.insert(A.end(), 0);
        vector<int> lm(n+1,0), rm(n+1,0);
        stack<int> st; st.push(0);
        for (int i=1; i<=n; i++) {
            while (!st.empty() && A[st.top()] >= A[i]) st.pop();
            lm[i]=st.top();
            st.push(i);
        }
        st=stack<int>(); st.push(n+1);
        for (int i=n; i; i--) {
            while (!st.empty() && A[st.top()] >= A[i]) st.pop();
            rm[i]=st.top();
            st.push(i);
        }
        k++;
        int ans=0;
        for (int i=1; i<=n; i++) {
            if (lm[i] < k && k < rm[i]) 
                ans=max(ans, (rm[i]-lm[i]-1) * A[i]);
        }
        return ans;
    }
};
posted @ 2020-10-26 21:39  童年の波鞋  阅读(86)  评论(0编辑  收藏  举报