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

127 阅读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


思路解析

这个问题可以转化为经典的“柱状图中最大的矩形”问题。我们需要找到一个方法来计算给定数组中所有可能的 kk 个连续元素形成的矩形的最大面积。一种有效的方法是使用单调栈(Monotonic Stack)来解决这个问题。

  1. 单调栈的应用

    • 单调栈是一种特殊的栈结构,其中栈内的元素保持递增或递减的顺序。
    • 在本问题中,我们可以使用一个单调递增栈来存储每个柱子的高度索引。
    • 当遇到一个比栈顶元素小的高度时,说明当前栈顶元素不能再扩展了,此时可以计算以栈顶元素为高度的最大矩形面积。
  2. 算法步骤

    • 初始化一个空栈和一个变量 maxArea 用于记录最大矩形面积。

    • 遍历整个数组,对于每个元素:

      • 如果栈为空或当前元素大于等于栈顶元素,则将当前元素的索引入栈。
      • 否则,弹出栈顶元素,并计算以该元素为高度的最大矩形面积。
    • 最后处理栈中剩余的元素,计算相应的矩形面积。

  3. 时间复杂度

    • 由于每个元素最多只会被入栈和出栈一次,因此时间复杂度为 O(n)O(n)。

代码解析

  1. 初始化

    java
    深色版本
    Stack<Integer> stack = new Stack<>();
    int maxArea = 0;
    int i = 0;
    
    • 初始化一个空栈 stack 和变量 maxArea 用于记录最大矩形面积。
    • 变量 i 用于遍历数组。
  2. 主循环

    java
    深色版本
    while (i < n) {
        if (stack.isEmpty() || height[i] >= height[stack.peek()]) {
            stack.push(i++);
        } else {
            int top = stack.pop();
            int width = stack.isEmpty() ? i : i - stack.peek() - 1;
            int area = height[top] * width;
            maxArea = Math.max(maxArea, area);
        }
    }
    
    • 如果栈为空或当前元素大于等于栈顶元素,则将当前元素的索引入栈。
    • 否则,弹出栈顶元素,计算以该元素为高度的最大矩形面积。宽度由当前索引和下一个栈顶元素的索引决定。
  3. 处理剩余元素

    java
    深色版本
    while (!stack.isEmpty()) {
        int top = stack.pop();
        int width = stack.isEmpty() ? i : i - stack.peek() - 1;
        int area = height[top] * width;
        maxArea = Math.max(maxArea, area);
    }
    
    • 处理栈中剩余的元素,计算相应的矩形面积。

代码解答

import java.util.Stack;

public class Main {
    public static int solution(int n, int[] height) {
        // Edit your code here
        Stack<Integer> stack = new Stack<>();
        int maxArea = 0;
        int i = 0;
        
        while (i < n) {
            // 如果栈为空或者当前高度大于栈顶高度,则将当前高度的索引入栈
            if (stack.isEmpty() || height[i] >= height[stack.peek()]) {
                stack.push(i++);
            } else {
                // 否则,弹出栈顶元素,计算以栈顶元素为高度的最大矩形面积
                int top = stack.pop();
                int area = height[top] * (stack.isEmpty() ? i : i - stack.peek() - 1);
                maxArea = Math.max(maxArea, area);
            }
        }
        
        // 处理栈中剩余的元素
        while (!stack.isEmpty()) {
            int top = stack.pop();
            int area = height[top] * (stack.isEmpty() ? i : i - stack.peek() - 1);
            maxArea = Math.max(maxArea, area);
        }
        
        return maxArea;
    }

    public static void main(String[] args) {
        // Add your test cases here
        System.out.println(solution(5, new int[]{1, 2, 3, 4, 5}) == 9);
        System.out.println(solution(6, new int[]{5, 4, 3, 2, 1, 6}) == 9);
        System.out.println(solution(4, new int[]{4, 4, 4, 4}) == 16);
    }
}