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

63 阅读3分钟

问题分析

小S需要解决的问题是:给定一个数组 h1, h2, ..., hN,数组的每个元素代表某种高度。小S希望找出对于任意 k 个相邻元素,它们所能形成的最大矩形面积。具体来说,对于 k 个相邻的元素,定义其矩形的最大面积为: R(k)=k×min(h[i],h[i+1],...,h[i+k1])R(k) = k \times \min(h[i], h[i+1], ..., h[i+k-1])

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

解法分析

可以总结出以下几种解法:

  1. 暴力法

    • 遍历所有可能的 k 值,对于每个 k,计算所有 k 个相邻元素的最小值,并计算其矩形面积。
    • 时间复杂度为 O(N2)O(N^2),空间复杂度为 O(1)O(1)
  2. 单调栈法

    • 使用单调栈来计算每个元素左边和右边第一个比它小的元素的下标,从而确定以该元素为最小值的矩形面积。
    • 时间复杂度为 O(N)O(N),空间复杂度为 O(N)O(N)
  3. 动态规划法

    • 通过动态规划的方式,记录每个元素左边和右边第一个比它小的元素的下标,从而计算最大矩形面积。
    • 时间复杂度为 O(N)O(N),空间复杂度为 O(N)O(N)

代码实现

以下是基于单调栈法的Java代码实现:

import java.util.Stack;

public class Main {
    public static int solution(int n, int[] array) {
        int[] L = new int[n];
        int[] R = new int[n];
        
        // 初始化L和R数组
        for (int i = 0; i < n; i++) {
            L[i] = i;
            R[i] = i;
        }
        
        // 单调栈计算L(i),从左到右
        Stack<Integer> stack = new Stack<>();
        for (int i = 0; i < n; i++) {
            while (!stack.empty() && array[stack.peek()] >= array[i]) {
                stack.pop();
            }
            L[i] = stack.empty() ? 0 : stack.peek() + 1;
            stack.push(i);
        }
        
        // 清空栈用于计算R(i)
        stack.clear();
        
        // 单调栈计算R(i),从右到左
        for (int i = n - 1; i >= 0; i--) {
            while (!stack.empty() && array[stack.peek()] >= array[i]) {
                stack.pop();
            }
            R[i] = stack.empty() ? n - 1 : stack.peek() - 1;
            stack.push(i);
        }
        
        // 计算 MAX(i) = (R(i) - L(i) + 1) * array[i] 并找出最大值
        int maxArea = 0;
        for (int i = 0; i < n; i++) {
            maxArea = Math.max(maxArea, (R[i] - L[i] + 1) * array[i]);
        }
        
        return maxArea;
    }

    public static void main(String[] args) {
        // 测试样例
        System.out.println(solution(5, new int[]{5, 4, 3, 4, 5})); // 输出: 8
        System.out.println(solution(6, new int[]{2, 1, 4, 3, 6, 5})); // 输出: 15
        System.out.println(solution(7, new int[]{1, 2, 3, 4, 5, 6, 7})); // 输出: 0
    }
}

学习感悟

  1. 算法复杂度分析

    • 暴力法虽然简单,但时间复杂度较高,不适合大规模数据。
    • 单调栈法和动态规划法在时间复杂度上都有显著优势,适合处理大规模数据。
  2. 数据结构的应用

    • 单调栈是一种非常强大的数据结构,适用于解决许多与区间最值相关的问题。
    • 动态规划则通过记录中间结果,避免了重复计算,提高了效率。
  3. 代码优化

    • 在实际编程中,合理使用数据结构和算法可以大大提升代码的执行效率。
    • 例如,通过预处理数组,减少不必要的计算,可以进一步优化代码性能。
  4. 问题抽象与解决

    • 将实际问题抽象为数学模型,并找到合适的算法来解决,是编程的核心能力。
    • 在解决复杂问题时,分解问题、逐步求解是常用的方法。

通过以上分析和代码实现,我们可以看到如何利用单调栈来高效地解决最大矩形面积问题,并从中学习到算法设计和数据结构应用的重要性。