单调栈——84. 柱状图中最大的矩形(下)

256 阅读2分钟

「这是我参与2022首次更文挑战的第3天,活动详情查看:2022首次更文挑战」。

题目描述

前文说了可以使用两次单调栈来解决问题

思路分析

前面使用maxRet记载最大值,并通过如下代码对遍历一遍后还在栈中的元素求值

if(!stk.empty()){ 
    int s = stk.top() + 1; 
    while(!stk.empty()){ 
        int tmp = stk.top(); 
        stk.pop(); 
        maxRet = max((s - tmp) * heights[tmp], maxRet); 
    } 
}

但是如果通过先求两边第一个比自己低的节点的索引就需要使用两个数组存储了。之前的代码实现了求每个节点右边的第一个比自己低的节点索引。但现在需要考虑如果这个节点不存在(比如说数组是一个单调递增数组),那么从计算角度考虑应该补充为length - 1。 同理,我们在求左边第一个比自己低的节点索引的时候,应该使用0作为补全。

需要注意的是,计算矩形的面积时宽的表示是arr[i] - arr1[i] + 1。

具体实现

int largestRectangleArea(vector<int>& heights) {
        stack<int> stk;
        int maxRet = 0;
        int length = heights.size();
        vector<int> arr(length);
        vector<int> arr1(length);
        for(int i = 0; i < length; i++){
            arr[i] = length - 1;
            arr1[i] = 0;
        }
        
        for (int i = 0; i < heights.size(); i ++){
            while(!stk.empty() && heights[stk.top()] > heights[i]) {
                int tmp = stk.top(); stk.pop();
                // maxRet = max((i -  tmp) * heights[tmp], maxRet);
                arr[tmp] = i - 1;
            }
        stk.push(i);
        }    
        //归零
        while(!stk.empty()) {
            stk.pop();
        }
        
        for(int i = length - 1; i >= 0; i --){
             while(!stk.empty() && heights[stk.top()] > heights[i]) {
                 int tmp = stk.top(); stk.pop();
                // maxRet = max((tmp -  i) * heights[tmp], maxRet);
                arr1[tmp] = i + 1;
             }
             stk.push(i);
        }
        for(int i = 0; i < length; i++){
            // cout << arr[i] << " "<< arr1[i] << endl;
            maxRet = max((arr[i] - arr1[i] + 1) * heights[i], maxRet);
        }
         
        return maxRet;
    }

总结

在初步理解题意后,我们将题目的描述梳理成某idx距符合条件M的idx1idx_1的最近距离的格式,再去实现单调栈就很简单了,同时我们也可以知道,单调栈中的单调方式就是M的反向,比如找到第一个比自己低的节点,单调栈就存储比自己高的节点。