青训营 X 豆包MarsCode 技术训练营 | 豆包MarsCode AI 刷题 | 16.最大矩形面积问题

67 阅读3分钟

问题相关

问题描述

小S最近在分析一个数组 h1,h2,...,hNh_1,h_2,...,h_N,数组的每个元素代表某种高度。小S对这些高度感兴趣的是,当我们选取任意k个相邻元素时,如何计算它们所能形成的最大矩形面积。 对于k个相邻的元素,我们定义其矩形的最大面积为:
R(k)=k×min(h[i],h[i+1],...,h[i+k1])R(k)=k×min(h[i],h[i+1],...,h[i+k−1]) 即,R(k)R(k)的值为这kk个相邻元素中的最小值乘以kk。现在,小S希望你能帮他找出对于任意kkR(k)R(k)的最大值。

输入描述

  • 数组长度n
  • 一个整数数组array

返回

选取任意k个相邻元素后,所计算出的能形成最大矩形的面积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

解题思路

这道题基于单调栈的解题思路,目的是找到每个柱子左右两边第一个小于该柱子的柱子。对于这种一维数组,要寻找任一个元素的右边或者左边第一个比自己大或者小的元素的位置,此时我们就要想到可以用单调栈了。时间复杂度为O(n)。单调栈的本质是时间换空间,需要一个额外的栈来记录右边第一个比当前元素小的元素,优点由此可以看出来只需要遍历一次整个数组。
单调栈中记录的是我们遍历过的元素,因为我们遍历数组时,并不知道之前遍历过哪些元素,此时便需要一个容器,这里使用栈,来进行记录。 而我们单调栈中元素的存放顺序是怎样的呢,因为我们要寻找的是每个柱子左右两边第一个小于该柱子的柱子,所以我们的单调栈从栈头到栈底的顺序应该是从大到小的顺序。

单调栈.png 有了对单调栈内部元素的顺序理解,接下来就是对逻辑的处理了,主要分为以下三种情况:

  1. 当前元素大于栈顶元素
  2. 当前元素等于栈顶元素
  3. 当前元素小于栈顶元素

对于面积的组成,通过单调栈的演示也可以看出来,是由栈顶元素和栈顶元素的下一个元素以及要入栈的三个元素组成了要求的最大的面积的高度(array[st.top()])和宽度(索引的差值),由此我们可以写出下面的代码

int solution(int n, std::vector<int> A) {
    // Edit your code here
    A.insert(A.begin(), 0);
    A.push_back(0);
    stack<int> st;
    int result = 0;
    st.push(0);
    for (int i = 1; i < A.size(); i++){
        if (A[i] > A[st.top()]) {
            st.push(i);
        } else if (A[i] == A[st.top()]) {
            st.push(i);
        } else {
            while (!st.empty() && A[i] < A[st.top()]) {
                int mid = st.top();
                st.pop();
                if (!st.empty()) {
                    int left = st.top();
                    int right = i;
                    int w = right - left - 1;
                    int h = A[mid];
                    result = max(result, w * h);
                }
            }
            st.push(i);
        }
    }
    
    return result;
}

注意在最开始进行遍历之前,在A的开头和结尾都添加了一个0,对于结尾处添加0,目的是为了防止栈中元素满足递增但是没有满足最后进行计算的逻辑。添加一个0后,可以走到else判定逻辑下从而计算出面积。

顺序递增.png

对于开头处添加0,如果数组本身是降序的例如[5,4,3,2,1],在进行第一轮判断时4<5,走到逻辑else处的判断,但此时的left变量却访问不到,即会向栈中取空值,依次下去,我们会迟迟得不到left变量,那么最后的计算结果也一定是0。
精简代码可以自己自行编写,我这样写是为了将步骤更清晰的凸显出来有利于自己思路的梳理。