最大矩形面积问题| 豆包MarsCode AI刷题

30 阅读3分钟

问题描述

小S最近在分析一个数组 h1,h2,...,hNh1​,h2​,...,hN​,数组的每个元素代表某种高度。小S对这些高度感兴趣的是,当我们选取任意 kk 个相邻元素时,如何计算它们所能形成的最大矩形面积。

对于 kk 个相邻的元素,我们定义其矩形的最大面积为:

R(k)=k×min(h[i],h[i+1],...,h[i+k−1])R(k)=k×min(h[i],h[i+1],...,h[i+k−1])

即,R(k)R(k) 的值为这 kk 个相邻元素中的最小值乘以 kk。现在,小S希望你能帮他找出对于任意 kk,R(k)R(k) 的最大值。


测试样例

样例1:

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

样例2:

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

样例3:

输入:n = 4, array = [4, 4, 4, 4]
输出:16

问题理解

我们需要在一个数组中找到任意 k 个相邻元素所能形成的最大矩形面积。这个矩形面积的计算方式是:k 个相邻元素中的最小值乘以 k

数据结构选择

由于我们需要频繁地查找最小值,并且需要遍历所有可能的 k 值(从 1 到 n),我们可以考虑使用以下数据结构和算法:

  1. 滑动窗口:用于在固定窗口大小 k 的情况下,快速计算窗口内的最小值。
  2. 单调栈:用于在 O(n) 时间内找到每个元素作为最小值时,能够形成的最大矩形面积。

算法步骤

  1. 滑动窗口法

    • 对于每个可能的 k(从 1 到 n),使用滑动窗口来计算每个窗口内的最小值,并计算矩形面积。
    • 记录每个 k 对应的最大矩形面积,最终取最大值。
  2. 单调栈法

    • 使用单调栈来维护一个递增的栈,栈中存储数组元素的索引。
    • 当遇到一个比栈顶元素小的元素时,弹出栈顶元素,并计算以该元素为最小值的矩形面积。
    • 最终取所有计算出的矩形面积中的最大值。

选择算法

  • 滑动窗口法:简单直观,但时间复杂度为 O(n^2),适用于 n 较小的情况。
  • 单调栈法:时间复杂度为 O(n),适用于 n 较大的情况。

建议

可以先尝试实现滑动窗口法,如果发现性能不足,再考虑使用单调栈法进行优化。

完整代码

 import java.util.*;

public class Main {
    public static int solution(int n, int[] A) {
        // 左边界和右边界
        int[] left = new int[n];   // 左边第一个比当前值小的索引
        int[] right = new int[n];  // 右边第一个比当前值小的索引
        Arrays.fill(left, -1);
        Arrays.fill(right, n);

        // 计算左边界
        Stack<Integer> st = new Stack<>();
        for (int i = 0; i < n; ++i) {
            while (!st.empty() && A[st.peek()] >= A[i]) {
                st.pop();
            }
            if (!st.empty()) {
                left[i] = st.peek();
            }
            st.push(i);
        }

        // 清空栈用于计算右边界
        st.clear();
        for (int i = n - 1; i >= 0; --i) {
            while (!st.empty() && A[st.peek()] >= A[i]) {
                st.pop();
            }
            if (!st.empty()) {
                right[i] = st.peek();
            }
            st.push(i);
        }

        // 计算结果
        int result = 0;
        for (int i = 0; i < n; ++i) {
            int length = right[i] - left[i] - 1;  // 当前元素能覆盖的区间长度
            result = Math.max(result, length * A[i]);
        }

        return result;
    }

    public static void main(String[] args) {
        // 测试用例
        int[] A_case1 = {1, 2, 3, 4, 5};
        System.out.println(solution(5, A_case1) == 9);  // 期望输出 true

        int[] A_case2 = {3, 1, 6, 4, 5, 2};
        System.out.println(solution(6, A_case2));  // 期望输出 12
    }
}