方法一(双指针)

思路展示

本题要记录记录每个柱子 左边第一个小于该柱子的下标,而不是左边第一个小于该柱子的高度。

所以需要循环查找,也就是下面在寻找的过程中使用了while

示例代码

class Solution {
public:
    int largestRectangleArea(vector<int>& heights) {
        int len=heights.size();
        // 记录每个柱子 左边第一个小于该柱子的下标
        vector<int> minLeftIndex(len+1);
        minLeftIndex[0]=-1;// 注意这里初始化,防止下面while死循环
        for (int i = 1; i < len; ++i) {
            //看其前一个的高度
            int t=i-1;
            while(t>=0&&heights[t]>=heights[i]){
                //更新其前一个下标
                t=minLeftIndex[t];
            }
            minLeftIndex[i]=t;
        }

        vector<int> minrightIndex(len+1);
        minrightIndex[len-1]=len;
        for (int i = len-2; i >=0; --i) {
            //看其后一个的高度
            int t=i+1;
            while(t<len&&heights[t]>=heights[i]){
                //更新其前一个下标
                t=minrightIndex[t];
            }
            minrightIndex[i]=t;
        }
        int res=0;
        for(int i=0;i<len;i++){
            int sum=heights[i]*(minrightIndex[i]-minLeftIndex[i]-1);
            res=max(sum,res);
        }
        return res;
    }
};
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.

效果展示

LeetCode---84. 柱状图中最大的矩形(双指针or单调栈)(求左右两边第一个小于该高度的下标)(栈内元素从低到顶依次减小)(数组最前最后加0,防止有些情况涉及不到)_入栈

方法二(单调栈)

思路展示

题解42. 接雨水 (opens new window)中我讲解了接雨水的单调栈从栈头(元素从栈头弹出)到栈底的顺序应该是从小到大的顺序。那么因为本题是要找每个柱子左右两边第一个小于该柱子的柱子,所以从栈头(元素从栈头弹出)到栈底的顺序应该是从大到小的顺序!

LeetCode---84. 柱状图中最大的矩形(双指针or单调栈)(求左右两边第一个小于该高度的下标)(栈内元素从低到顶依次减小)(数组最前最后加0,防止有些情况涉及不到)_leetcode_02

此时大家应该可以发现其实就是栈顶和栈顶的下一个元素以及要入栈的三个元素组成了我们要求最大面积的高度和宽度

细心的录友会发现,我在 height数组上后,都加了一个元素0, 为什么这么做呢?

首先来说末尾为什么要加元素0?

如果数组本身就是升序的,例如[2,4,6,8],那么入栈之后 都是单调递减,一直都没有走 情况三 计算结果的哪一步,所以最后输出的就是0了。 如图:

LeetCode---84. 柱状图中最大的矩形(双指针or单调栈)(求左右两边第一个小于该高度的下标)(栈内元素从低到顶依次减小)(数组最前最后加0,防止有些情况涉及不到)_职场和发展_03

那么结尾加一个0,就会让栈里的所有元素,走到情况三的逻辑。

开头为什么要加元素0?

如果数组本身是降序的,例如 [8,6,4,2],在 8 入栈后,6 开始与8 进行比较,此时我们得到 mid(8),rigt(6),但是得不到 left。

(mid、left,right 都是对应版本一里的逻辑)

因为 将 8 弹出之后,栈里没有元素了,那么为了避免空栈取值,直接跳过了计算结果的逻辑。

之后又将6 加入栈(此时8已经弹出了),然后 就是 4 与 栈口元素 8 进行比较,周而复始,那么计算的最后结果resutl就是0。 如图所示:

LeetCode---84. 柱状图中最大的矩形(双指针or单调栈)(求左右两边第一个小于该高度的下标)(栈内元素从低到顶依次减小)(数组最前最后加0,防止有些情况涉及不到)_leetcode_04

所以我们需要在 height数组前后各加一个元素0。

示例代码

class Solution {
public:
    int largestRectangleArea(vector<int>& heights) {
        heights.push_back(0);
        heights.insert(heights.begin(),0);
        int len=heights.size();
        stack<int> stk;
        int res=0;
        for(int i=0;i<len;i++){
            while(!stk.empty()&&heights[stk.top()]>heights[i]){
                int topIndex=stk.top();
                stk.pop();
                //判断其左边还有没有元素
                if(stk.empty()){
                    break;
                }
                //在对 top 计算,left 变成新的 top
                //所以其不用出栈
                int leftIndex=stk.top();
                res=max(res,heights[topIndex]*(i-leftIndex-1));
                
            }
            stk.push(i);
        }
        return res;
    }
};
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.

效果展示

LeetCode---84. 柱状图中最大的矩形(双指针or单调栈)(求左右两边第一个小于该高度的下标)(栈内元素从低到顶依次减小)(数组最前最后加0,防止有些情况涉及不到)_职场和发展_05