单调栈:直方图中最大的矩形

单调栈:直方图中最大的矩形

www.acwing.com/file_system/file/content/whole/index/content/3682…

请添加图片描述

  • 对于第 i i i 个位置,在 lmax[i]​ 中,存储了从当前这个点向左延伸,能够延伸的最大长度,此处的延伸是指不受阻挡地向外扩展(即碰到比自己低的就停止)

  • 同理对于 rmax[i]​,存储了当前这个点向右侧延伸的最大长度

  • 注意以上两个数组所表示的数值不包含该点自身

  • 这样子对于第 i i i 个点,其所能扩展得到的最大矩形面积为 a r r [ i ] ∗ ( l m a x [ i ] + r m a x [ i ] + 1 ) arr[i]*(lmax[i]+rmax[i]+1) arr[i](lmax[i]+rmax[i]+1)

  • 可以思考一下为什么一定要取到 a r r [ i ] arr[i] arr[i],而不是比它更小一点的数值向外延伸

    • 假设取了比 a r r [ i ] arr[i] arr[i] 更小的一个数,记为 x x x,以 $x $ 为基准向两侧扩展得到的数组为 l m a x ′ [ i ] lmax'[i] lmax[i] r m a x ′ [ i ] rmax'[i] rmax[i]
    • 如果要使 x ∗ ( l m a x ′ [ i ] + r m a x ′ [ i ] + 1 ) > a r r [ i ] ∗ ( l m a x [ i ] + r m a x [ i ] + 1 ) x*(lmax'[i]+rmax'[i]+1) > arr[i]*(lmax[i]+rmax[i]+1) x(lmax[i]+rmax[i]+1)>arr[i](lmax[i]+rmax[i]+1)
    • 由于 x < a r r [ i ] x<arr[i] x<arr[i],那么一定要有 l m a x ′ [ i ] + r m a x ′ [ i ] > l m a x [ i ] + r m a x [ i ] ① lmax'[i]+rmax'[i]>lmax[i]+rmax[i] ① lmax[i]+rmax[i]>lmax[i]+rmax[i](必要条件)
    • 如果 ① 式成立,意味着一定存在一个 j ( j ≠ i ) j(j ≠i) j(j=i),使得 l m a x ′ [ i ] + r m a x ′ [ i ] = l m a x [ j ] + r m a x [ j ] lmax'[i]+rmax'[i]=lmax[j]+rmax[j] lmax[i]+rmax[i]=lmax[j]+rmax[j]
    • 那么最大值选取 $j $ 即可,即不用考虑小于 a r r [ i ] arr[i] arr[i] 的值,最后一定能找到最大结果
import java.util.*;
import java.io.*;

public class Main {
    static final int N = 100010;
    static long[] arr = new long[N];
    static int[] lmax = new int[N];
    static int[] rmax = new int[N];
    static int n;
    static int[] q = new int[N];
    static int top;

    public static void main(String[] args) throws Exception {
        while ((n = Reader.nextInt()) != 0) {
            for (int i = 0; i < n; i++) {
                arr[i] = Reader.nextLong();
            }

            // 向左能够延伸的长度,不包含本身
            // 使用单调栈,存放索引,每次寻找第一个高度比自己小的位置
            top = -1;
            for (int i = 0; i < n; i++) {
                while (top >= 0 && arr[q[top]] >= arr[i]) {
                    top--;
                }
                lmax[i] = top == -1 ? i : i - q[top] - 1;
                q[++top] = i;
            }

            // 向右能够延伸的长度,不包含本身
            top = -1;
            for (int i = n - 1; i >= 0; i--) {
                while (top >= 0 && arr[q[top]] >= arr[i]) {
                    top--;
                }
                rmax[i] = top == -1 ? n - 1 - i : q[top] - i - 1;
                q[++top] = i;
            }

            long res = 0;
            for (int i = 0; i < n; i++) {
                res = Math.max(res, arr[i] * (lmax[i] + rmax[i] + 1));
            }
            System.out.println(res);
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值