单调栈系列(最大乘积面积问题)|豆包MarsCode Al刷题

61 阅读2分钟

上一篇文章讲解了如何用维护一个单调栈来解决求子数组的最小值×\times长度的最大值问题,且如何处理当遍历之后一个元素栈不为空的处理技巧。最大矩形面积问题和上一题很相似,都可以用单调栈来解决。

问题描述

小R最近遇到了一个数组问题。他有一个包含 N个元素的数组,记作 a1,a2,...,aNa_1,a_2,...,a_N。为了分析这个数组的特性,小R定义了两个函数 L(i) 和 R(i),并希望通过这两个函数来找到一些有趣的结论。

  • L(i) 是满足以下条件的最大的 j 值:
  • j<i
  • a[j]>a[i]
  • 如果找不到这样的 j,那么 L(i)=0;如果有多个满足条件的 j,选择离 i 最近的那个。
  • R(i) 是满足以下条件的最小的 k 值:
  • k>i
  • a[k]>a[i]
  • 如果找不到这样的 k,那么 R(i)=0;如果有多个满足条件的 k,选择离 i 最近的那个。

最终,小R定义 MAX(i)=L(i)∗R(i),他想知道在 1≤i≤N 的范围内,MAX(i)的最大值是多少。


测试样例

样例1:

输入:n = 5, array = [5, 4, 3, 4, 5]
输出:8

样例2:

输入:n = 6, array = [2, 1, 4, 3, 6, 5]
输出:15

样例3:

输入:n = 7, array = [1, 2, 3, 4, 5, 6, 7]
输出:0

思路

这题如果题目读懂了,其实是一个求左右边界的问题,相当于a[i]表示[j, k]区间内的最小值,然后确定这个区间。上一题是确定这个区间内的最小值乘以长度的最大值,这题解题思路一行,只不过得到结果的方式不一,过程是一样的。

算法步骤

  1. 计算 L(i)

    • 从左到右遍历数组,使用栈来维护一个递减序列。
    • 对于每个元素 a[i],如果栈顶元素比 a[i] 小,则弹出栈顶元素,直到栈为空或者栈顶元素比 a[i] 大。
    • 栈顶元素的索引就是 L(i)
  2. 计算 R(i)

    • 从右到左遍历数组,使用栈来维护一个递减序列。
    • 对于每个元素 a[i],如果栈顶元素比 a[i] 小,则弹出栈顶元素,直到栈为空或者栈顶元素比 a[i] 大。
    • 栈顶元素的索引就是 R(i)
  3. 计算 MAX(i)

    • 遍历数组,计算 MAX(i) = L(i) * R(i),并记录最大值。
import java.util.*;
public class Main {
    public static int solution(int n, int[] array) {
        // Edit your code here
        Stack<Integer> stack = new Stack<>();
        int max = 0;
        for (int i = 0; i < n; i++) {
            while (!stack.isEmpty() && array[i] > array[stack.peek()]) {
                if (array[i] == stack.pop()) continue;
                int l = stack.isEmpty() ? -1 : stack.peek();
                max = Math.max(max, (l + 1) * (i + 1));
            }
            stack.push(i);
        }
        return max;
    }

    public static void main(String[] args) {
        // Add your test cases here

        System.out.println(solution(5, new int[]{5, 4, 3, 4, 5}) == 8);
    }
}

总结

求子数组边界问题用栈处理真的很优雅