做题笔记:最大矩形面积问题| 豆包MarsCode AI刷题

80 阅读5分钟

做题笔记:最大矩形面积问题

问题理解

题目要求我们分析一个数组,找出任意 k 个相邻元素所能形成的最大矩形面积。具体来说,对于任意 k 个相邻元素,矩形的最大面积定义为这 k 个元素中的最小值乘以 k。我们需要找到对于所有可能的 k,R(k) 的最大值。

数据结构与算法选择

为了高效地解决这个问题,我们可以使用滑动窗口和单调栈的结合。滑动窗口用于遍历所有可能的 k 值,而单调栈则用于在每个窗口内快速找到最小值。

  1. 滑动窗口:滑动窗口是一种常见的算法技巧,用于在数组或列表中处理连续的子数组或子序列。在这个问题中,滑动窗口帮助我们遍历所有可能的 k 值。
  2. 单调栈:单调栈是一种特殊的栈,栈内的元素保持单调递增或递减的顺序。在这个问题中,单调栈帮助我们在每个窗口内快速找到最小值。

算法步骤

  1. 初始化:首先,我们初始化一个最大面积变量 maxArea,用于存储最终的结果。
  2. 滑动窗口初始化:对于每个 k 值,我们从数组的第一个元素开始,初始化一个滑动窗口。窗口的大小为 k,我们使用一个双端队列(Deque)来维护窗口内的元素。
  3. 单调栈维护:在滑动窗口内,我们使用单调栈来维护窗口内的最小值。具体来说,我们保持栈内的元素单调递增,这样栈顶元素就是当前窗口的最小值。
  4. 滑动窗口处理:随着窗口的滑动,我们需要更新单调栈。具体来说,当窗口滑动到下一个元素时,我们需要移除不在窗口内的元素,并保持栈的单调性。
  5. 计算最大面积:在每个窗口内,我们计算当前窗口的最小值乘以 k,并更新 maxArea
  6. 返回结果:最终,我们返回 maxArea 作为结果。

代码详解

import java.util.*;

public class Main {
public static int solution(int n, int[] array) {
    int maxArea = 0;

    // 枚举 k 从 1 到 n
    for (int k = 1; k <= n; k++) {
        Deque<Integer> deque = new ArrayDeque<>();
        int currentMin = Integer.MAX_VALUE;

        // 滑动窗口初始化
        for (int i = 0; i < k; i++) {
            while (!deque.isEmpty() && array[deque.peekLast()] >= array[i]) {
                deque.pollLast();
            }
            deque.offerLast(i);
        }

        currentMin = array[deque.peekFirst()];
        maxArea = Math.max(maxArea, k * currentMin);

        // 滑动窗口处理
        for (int i = k; i < n; i++) {
            // 移除不在窗口内的元素
            if (!deque.isEmpty() && deque.peekFirst() <= i - k) {
                deque.pollFirst();
            }

            // 保持队列单调性
            while (!deque.isEmpty() && array[deque.peekLast()] >= array[i]) {
                deque.pollLast();
            }
            deque.offerLast(i);

            currentMin = array[deque.peekFirst()];
            maxArea = Math.max(maxArea, k * currentMin);
        }
    }

    return maxArea;
}

public static void main(String[] args) {
    System.out.println(solution(5, new int[]{1, 2, 3, 4, 5}) == 9);
    System.out.println(solution(6, new int[]{6, 5, 4, 3, 2, 1}) == 12);
    System.out.println(solution(6, new int[]{1, 3, 2, 1, 2, 4}) == 6);
}
}
#### 总结知识点
  1. 滑动窗口:滑动窗口是一种常见的算法技巧,用于处理连续的子数组或子序列。它通常用于解决需要遍历所有可能的子数组或子序列的问题。
  2. 单调栈:单调栈是一种特殊的栈,栈内的元素保持单调递增或递减的顺序。它通常用于在数组或列表中快速找到某个范围内的最小值或最大值。
  3. 双端队列(Deque) :双端队列是一种可以在两端进行插入和删除操作的队列。它通常用于实现滑动窗口和单调栈。

个人思考与分析

在这个问题中,滑动窗口和单调栈的结合是一个非常巧妙的解决方案。滑动窗口帮助我们遍历所有可能的 k 值,而单调栈则帮助我们在每个窗口内快速找到最小值。这种结合不仅提高了算法的效率,还使得代码更加简洁和易于理解。

对于入门同学来说,理解滑动窗口和单调栈的概念是非常重要的。这两个概念不仅在解决这个问题时非常有用,而且在其他许多算法问题中也有广泛的应用。因此,建议入门同学在学习算法时,重点掌握这两个概念,并通过大量的练习来加深理解。

此外,对于这个问题的解决,我们还可以考虑其他的数据结构和算法,例如动态规划。动态规划也可以用于解决这个问题,但它通常需要更多的空间和时间复杂度。因此,在实际应用中,我们需要根据具体的问题和需求来选择最合适的算法。

学习建议

  1. 多练习:算法的学习离不开大量的练习。建议入门同学多做一些与滑动窗口和单调栈相关的题目,通过实践来加深理解。
  2. 理解数据结构:数据结构是算法的基础。建议入门同学在学习算法之前,先掌握一些基本的数据结构,例如数组、链表、栈、队列等。
  3. 分析时间复杂度:在解决算法问题时,时间复杂度是一个非常重要的指标。建议入门同学在编写代码时,注意分析算法的时间复杂度,并尽量优化算法的效率。
  4. 参考优秀代码:在学习算法时,参考优秀的代码是一个非常有效的方法。建议入门同学多阅读一些优秀的代码,并尝试理解其中的思路和技巧。

通过以上的学习和实践,相信入门同学可以更好地掌握滑动窗口和单调栈的概念,并在解决算法问题时更加得心应手。