刷题实践之基础栈| 豆包MarsCode AI 刷题

128 阅读4分钟

解题思路与代码实现

问题描述

小S最近在分析一个数组 ℎ1,ℎ2,…,ℎ𝑁,数组的每个元素代表某种高度。小S对这些高度感兴趣的是,当我们选取任意 𝑘k 个相邻元素时,如何计算它们所能形成的最大矩形面积。对于 𝑘k 个相邻的元素,我们定义其矩形的最大面积为:

𝑅(𝑘)=𝑘×min⁡(ℎ[𝑖],ℎ[𝑖+1],…,ℎ[𝑖+𝑘−1])

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

测试样例

  1. 样例1:
    • 输入: n = 5, array = [1, 2, 3, 4, 5]
    • 输出: 9
  2. 样例2:
    • 输入: n = 6, array = [5, 4, 3, 2, 1, 6]
    • 输出: 9
  3. 样例3:
    • 输入: n = 4, array = [4, 4, 4, 4]
    • 输出: 16

解题思路

这个问题与直方图中最大的矩形面积问题非常相似。我们可以利用类似的方法,通过单调栈来高效地解决。

步骤解析

  1. 使用单调栈:

    • 我们维护一个单调递增的栈,栈中存储的是柱子的索引。
    • 当当前柱子的高度小于栈顶柱子的高度时,意味着栈顶柱子找到了右边第一个比它低的柱子。
    • 弹出栈顶柱子,计算以该柱子为最小高度的最大面积。
  2. 计算面积:

    • 对于弹出的柱子 ( h[top] ),其宽度为当前索引 ( i ) 与栈顶新的柱子索引之间的差值减一。
    • 计算面积 ( h[top] \times width ),并更新最大面积。
  3. 遍历结束后的处理:

    • 遍历完所有柱子后,可能还有柱子留在栈中,这些柱子的右边没有比它们更低的柱子。
    • 依次弹出这些柱子,并计算相应的面积。
  4. 最终结果:

    • 最大的面积即为所求的最大 ( R(k) )。

算法复杂度

  • 时间复杂度: ( O(N) ),每个柱子最多被压入和弹出栈一次。
  • 空间复杂度: ( O(N) ),用于栈的空间。

代码实现

import java.util.ArrayDeque;
import java.util.Deque;

public class Main {
    public static int solution(int n, int[] array) {
        // Edit your code here
        // 使用栈来存储索引
        Deque<Integer> stack = new ArrayDeque<>();
        int maxArea = 0;
        int i = 0;

        while (i < n) {
            // 如果当前柱子高度大于栈顶柱子的高度,或者栈为空,则将当前柱子索引压入栈
            if (stack.isEmpty() || array[i] >= array[stack.peek()]) {
                stack.push(i++);
            } else {
                // 弹出栈顶柱子,计算面积
                int top = stack.pop();
                // 计算宽度,注意这里使用 '=' 号进行赋值
                int width = stack.isEmpty() ? i : i - stack.peek() - 1;
                // 计算面积并更新最大面积
                maxArea = Math.max(maxArea, array[top] * width);
            }
        }

        // 处理栈中剩余的柱子
        while (!stack.isEmpty()) {
            int top = stack.pop();
            int width = stack.isEmpty() ? i : i - stack.peek() - 1;
            maxArea = Math.max(maxArea, array[top] * width);
        }

        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);
    }
}

代码说明

  1. 栈的作用:

    • 栈中存储的是柱子的索引,且栈内的柱子高度保持递增。
    • 通过这个性质,我们可以快速找到每个柱子的左边和右边第一个比它低的柱子。
  2. 遍历过程:

    • 当当前柱子的高度大于或等于栈顶柱子的高度时,将其索引压入栈。
    • 否则,弹出栈顶柱子,并计算以弹出柱子为最小高度的矩形面积。
    • 继续这个过程,直到当前柱子的高度不再小于栈顶柱子的高度。
  3. 计算面积:

    • 对于弹出的柱子 ( h[top] ),其左边界是当前栈顶柱子(如果有的话),右边界是当前柱子。
    • 宽度 ( width = i - stack.peek() - 1 )。
  4. 处理剩余柱子:

    • 遍历完成后,栈中可能还有柱子没有处理完,需要依次弹出并计算面积。
  5. 测试样例验证:

    • 样例1:
      • 输入:n = 5, array = [1, 2, 3, 4, 5]
      • 最大面积为 9,对应子数组 [3, 4, 5],最小值为 3,面积为 3 * 3 = 9
    • 样例2:
      • 输入:n = 6, array = [5, 4, 3, 2, 1, 6]
      • 最大面积为 9,对应子数组 [5, 4, 3],最小值为 3,面积为 3 * 3 = 9
    • 样例3:
      • 输入:n = 4, array = [4, 4, 4, 4]
      • 最大面积为 16,对应整个数组,最小值为 4,面积为 4 * 4 = 16

总结

通过使用单调栈的方法,我们能够高效地找到每个柱子前面和后面第一个比它低的柱子,从而计算出所能形成的最大矩形面积。该算法的时间复杂度为 O(N),适用于大规模的数据处理。