【单调栈】柱状图中最大的矩形

在这里插入图片描述
在这里插入图片描述

动态规划

本题要记录每个柱子左边第一个小于该柱子的下标,以及右边第一个小于该柱子的下标,而不是第一个小于该柱子的高度。然后使用两个下标之间的差作为矩形的底(底不包括两个下标所在位置),当前柱子的高度作为矩形的高,计算当前矩形面积

  • 左侧没有比当前柱子低的柱子,说明使用当前柱子为高的矩形的底部可以延申到最左侧,下标记为-1;
  • 右侧没有比当前柱子低的柱子,说明使用当前柱子为高的矩形的底部可以延申到最右侧,下标记为 n
    在这里插入图片描述
class Solution {
public:
    int largestRectangleArea(vector<int>& heights) {
        int n = heights.size();
        vector<int> l_idx(n, -1);  // 左侧没有比当前柱子低的,则下标为-1
        vector<int> r_idx(n, n);   // 右侧没有比当前柱子低的,则下标为 n
        // 从左往右遍历
        for(int i = 1; i < n; i++){
            int j = i - 1;
            while(j >= 0 && heights[j] >= heights[i]) j = l_idx[j];  // 利用数组快速回溯
            l_idx[i] = j;
        }
        for(int i = n - 2; i >= 0; i--){
            int j = i + 1;
            while(j < n && heights[j] >= heights[i]) j = r_idx[j];
            r_idx[i] = j;
        }

        int ans = 0;
        for(int i = 0; i < n; i++){
            ans = max(ans, heights[i] * (r_idx[i] - l_idx[i] - 1));
        }
        return ans;
    }
};

单调栈

本题是要找每个柱子左右两边第一个小于该柱子的下标,所以从栈底到栈顶的顺序应该是从小到大的顺序,这样栈顶的两个元素和即将入栈的元素就能形成小-大-小,这样就能找到左右两边第一个小于当前柱子的下标

  • 情况一:当前遍历的元素heights[i]小于栈顶元素heights[st.top()],计算矩形面积
  • 情况二:当前遍历的元素heights[i]等于栈顶元素heights[st.top()],因为要找的是左侧第一个比当前遍历元素小的柱子,且栈内元素用作矩形宽度的做下标,要使用最靠右的下标作为矩形的边界,所以应该先pop,再push(i)
  • 情况三:当前遍历的元素heights[i]大于栈顶元素heights[st.top()],直接入栈
int largestRectangleArea(vector<int>& heights) {
    int n = heights.size();
    int ans = 0;
    stack<int> st;
    st.push(0);

    for(int i = 1; i < n; i++){
        if(heights[i] > heights[st.top()]){
            st.push(i);
        }else if(heights[i] == heights[st.top()]){
            st.pop();   // 写和不写都行,结果一样,不写会重复计算面积相同的结果,写了不会重复计算
            st.push(i);
        }else{
            while(!st.empty() && heights[i] < heights[st.top()]){
                int h_idx = st.top();
                st.pop();
                int l_idx = -1;
                if(!st.empty()){
                    l_idx = st.top();
                }   
                int r_idx = i;
                ans = max(ans, heights[h_idx] * (r_idx - l_idx - 1));
            }
            st.push(i);
        }
    }
    // 最后需要处理底部延申到最右侧的矩形,右下标r_idx为n
    int r_idx = n;
    while (!st.empty()) {
        int h_idx = st.top();
        st.pop();
        int l_idx = -1;
        if (!st.empty()) {
            l_idx = st.top();
        }
        ans = max(ans, heights[h_idx] * (r_idx - l_idx - 1));
    }
    return ans;
}

精简后的代码

class Solution {
public:
    int largestRectangleArea(vector<int>& heights) {
        int n = heights.size();
        int ans = 0;
        stack<int> st;
        st.push(0);
        // 每次循环计算以i为右下标的矩形的面积
        for(int i = 1; i <= n; i++){
            while(!st.empty()){
                if(i < n && heights[i] >= heights[st.top()]){
                    // 当前柱子的高度heights[i]不小于栈顶柱子高度,直接入栈,不用计算矩形面积
                    break;
                }
                int h_idx = st.top();  // 栈顶元素取出,计算以当前柱子为高的矩形面积
                st.pop();
                int l_idx = -1;        // 栈空时,表示左侧没有柱子,则左侧下标记为l_idx
                if(!st.empty()){
                	// 栈不空时,取出左侧下标l_idx
                    l_idx = st.top();
                }
                // 栈顶下标表示矩形高度,栈顶前一个元素表示矩形左侧下标l_idx,当前下标i表示矩形的右侧下标
                ans = max(ans, heights[h_idx] * (i - l_idx - 1));
            }
            if(i < n) st.push(i);
        }
        return ans;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

bugcoder-9905

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值