16.求解最大矩形面积问题 | 豆包MarsCode AI刷题

45 阅读5分钟

问题背景

数组中的每个元素代表某种高度。对于给定的数组,问题要求我们计算任意k个相邻元素形成的矩形的最大面积,最终找出最大矩形的面积。

在数学上,对于任意k个相邻元素,我们定义它们形成的矩形的最大面积为:R(k) = k * min(h[i], h[i+1], ..., h[i+k-1]),其中h[i]表示第i个元素,min代表取这k个元素中的最小值,而k是这k个元素的个数。

目标是找到最大值R(k)在所有可能的k值中的最大值。

思路与分析

这个问题的本质是求解一个类似于“柱状图最大矩形面积”的问题。我们可以将每个数组元素看作是柱状图中的一根柱子,计算任意一段柱子所能形成的矩形面积。考虑到每个矩形的高度取决于该区间中的最小高度,因此在计算每个k个相邻元素的矩形面积时,我们要用最小高度乘以这个区间的长度。

关键点

  1. 暴力求解的不可行性对于每一个k,我们需要遍历数组中的所有可能的连续子数组,计算它们的最小值并乘以k。这显然是一个O(n²)的解决方案。由于n的最大值可能很大(比如达到10^5),这种暴力解法在时间上会显得不可接受。
  2. 利用栈优化计算由于矩形的最大面积与柱子的高度相关,而最小的高度决定了矩形的高度,因此我们可以通过一个栈来优化求解过程。栈用于存储柱子(数组元素)的索引,通过栈的特性,可以快速找到每个柱子能延伸的最大宽度。

栈的应用

栈在这里的作用是辅助我们找到以某个元素为最小高度的最大矩形宽度。具体地说,对于每个数组元素,栈会保持一个递增的顺序。当遇到一个比栈顶元素更小的元素时,我们就可以确定栈顶元素能形成的矩形的最大宽度,从而计算其面积。

算法流程

  1. 初始化我们用一个栈来辅助计算,栈的作用是存储当前尚未计算面积的柱子的索引。max_area用于保存当前的最大矩形面积。
  2. 遍历数组对于每个元素,我们将其索引压入栈中,直到我们遇到比栈顶元素小的元素为止。当这种情况发生时,我们就可以从栈中弹出一个元素,并计算以该元素为最小高度的矩形面积。此时,矩形的宽度是从栈顶下一个元素的位置到当前元素的位置之间的区间。
  3. 处理剩余元素数组遍历完后,栈中可能还有一些元素。我们继续弹出栈顶元素,并计算它们能形成的矩形面积,直到栈为空。

代码实现

以下是这个问题的解决代码:

  
  #include <iostream>
  #include <vector>
  #include <stack>
  #include <algorithm>int solution(int n, std::vector<int> A) {
      std::stack<int> s;  // 用于存储数组索引的栈
      int max_area = 0;   // 用于存储最大矩形面积
      int i = 0;          // 数组索引
  ​
      while (i < n) {
          // 如果栈为空或者当前元素大于等于栈顶元素,入栈
          if (s.empty() || A[i] >= A[s.top()]) {
              s.push(i++);
          } else {
              // 弹出栈顶元素,并计算以栈顶元素为最小值的矩形面积
              int tp = s.top();
              s.pop();
              int area_with_top = A[tp] * (s.empty() ? i : i - s.top() - 1);
              max_area = std::max(max_area, area_with_top);
          }
      }
  ​
      // 处理栈中剩余的元素
      while (!s.empty()) {
          int tp = s.top();
          s.pop();
          int area_with_top = A[tp] * (s.empty() ? i : i - s.top() - 1);
          max_area = std::max(max_area, area_with_top);
      }
  ​
      return max_area;
  }
  ​
  int main() {
      std::vector<int> A_case1 = {1, 2, 3, 4, 5};
      std::cout << (solution(5, A_case1) == 9) << std::endl;
      return 0;
  }

代码解析

  1. 栈的使用栈用于存储当前的柱子索引。当我们发现当前元素比栈顶元素小的时候,我们就弹出栈顶元素,并计算以该元素为最小高度的矩形面积。这个过程反映了我们在找到最小高度时,能够快速确定矩形的宽度。
  2. 面积的计算对于每个从栈中弹出的元素,我们计算其对应的矩形面积。面积的宽度是从栈中下一个元素到当前元素的距离,而高度是弹出元素对应的高度。我们不断更新max_area,确保记录下当前的最大矩形面积。
  3. 处理剩余元素数组遍历完后,栈中可能还有未处理的元素。我们继续弹出栈顶元素并计算对应的矩形面积,直到栈为空。

思考与总结

通过栈的优化,我们将原本的O(n²)时间复杂度降到了O(n)。栈帮助我们有效地找到了每个元素作为最小高度时能够延伸的最大宽度。这种方法不仅解决了面积计算的问题,还有效避免了暴力求解带来的时间复杂度过高的困扰。

总的来说,这个问题的关键在于如何利用栈来快速计算每个区间的最大矩形面积。通过栈,我们避免了重复的计算,从而使得时间复杂度得以优化。在解决类似问题时,栈的巧妙应用常常能帮助我们从暴力解法中跳脱出来,找到更加高效的解法。