Largest Rectangle in a Histogram HDU - 1506 (DP 单调栈 思维) 详细题解

在这里插入图片描述

题意: 给出若干连续的矩形高度(如图), 宽度为1, 求最大的矩形面积

题解: 这是一道非常不错的题目, 简单总结一下这类题的惯用思路
对于这种拿到就有思路的题目, 我们不妨先考虑惯用思路, 也就是枚举每一个hi, 再分别左右扫描, 很显然n^2的复杂度, 一定会超时, 我们不妨再来考虑哪里可以拿来优化.
这一个思路超时的关键就在于里面似乎存在了大量的重复计算, 可以试想扫描hi高度时, 很多比较已经在hi-1扫描过了, 所以我们需要减少重复计算, 毫无疑问就要采用空间来换时间咯.
对于区间求最值的优化, 我们可以采用dp或单调栈/单调队列优化

  • 定义Li, Ri为以hi为最低点时, 左右不小于hi的最远坐标(包括其自身)
  • 使用dp或单调栈优化
  • 求得max( h[i]*(r[i]-l[i]+1) )即为答案

dp版本, 状态转移方程为l[i] = {l[ l[i]-1 ] | h[ l[i]-1 ] >= h[i] }, r[i] = {r[ r[i]+1 ] | h[ r[i]-1 ] >= h[i] }

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
#define ms(x, n) memset(x,n,sizeof(x));
typedef  long long LL;
const LL maxn = 1e5+10;

int n, h[maxn];
int l[maxn], r[maxn]; //以hi为最低点左右最远不小于hi的坐标
int main()
{
    while(cin >> n && n){
        for(int i = 1; i <= n; i++){
            cin >> h[i];
            l[i] = r[i] = i; //初始化
        }

            for(int i = 2; i <= n; i++){
                //向左遍历直至发现小于hi的点, 同时避免重复计算
                while(h[l[i]-1] >= h[i] && l[i]>0)
                    l[i] = l[l[i]-1];
            }
            for(int i = n-1; i > 0; i--){
                //向右遍历直至发现小于hi的点, 同时避免重复计算
                while(h[r[i]+1] >= h[i] && r[i]<n)
                    r[i] = r[r[i]+1];
            }
            LL ans = 0;
            for(int i = 1; i <= n; i++)
                ans = max(ans, (LL)h[i]*(r[i]-l[i]+1));
            cout << ans << endl;
    }

	return 0;
}

单调栈版本

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N = 100000 + 100;
stack<int> S;
ll h[N];
int R[N], L[N]; //以hi为最低点左右两边最远不小于其的坐标

int main() {
    int n;
    while(~scanf("%d", &n) && n) {
        for(int i = 1 ; i <= n ; i++)
            scanf("%I64d", &h[i]);

        while(S.size())
            S.pop();

        //利用单调栈取得以hi为最低点的左右边界
        for(int i = 1 ; i <= n ; i++) {
            while(S.size() && h[S.top()] >= h[i])
                S.pop();

            if(S.empty())
                L[i] = 1;
            else
                L[i] = S.top()+1;
            S.push(i);
        }

        while(S.size())
            S.pop();
        for(int i = n; i > 0 ; i--) {
            while(S.size() && h[S.top()] >= h[i])
                S.pop();

            if(S.empty())
                R[i] = n;
            else
                R[i] = S.top()-1;

            S.push(i);
        }

        ll ans = 0;
        for(int i = 1 ; i <= n ; i++) {
            ans = max(ans, h[i] * (R[i]-L[i]+1));
        }
        printf("%I64d\n", ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/a1097304791/article/details/86747802