当前位置: 首页 >  网络应用 >  吃透单调栈(2)——解两道Hard题:接雨水、柱状图中最大的矩形问题

吃透单调栈(2)——解两道Hard题:接雨水、柱状图中最大的矩形问题

导读:怎么想到要用单调栈的?.这类题目的数据通常是一维数组,要寻找任一个元素的右边或者左边第一个 比自己大 或者小 的元素的位置(寻找边界.),此时我们就要想到可以用单调栈了。.42. 接雨水.这道题就是要求解每一个柱子左边第一个比它高的柱子,以及右边第一个比它高的柱子,然后这两个柱子

怎么想到要用单调栈的?

这类题目的数据通常是一维数组,要寻找任一个元素的右边或者左边第一个 比自己 或者 的元素的位置(寻找边界 ),此时我们就要想到可以用单调栈了。

42. 接雨水

这道题就是要求解每一个柱子左边第一个比它高的柱子,以及右边第一个比它高的柱子,然后这两个柱子间形成的凹槽面积。

注意,是横向扫 来求面积。比如下图,4号柱左边第一个比它高的柱子是3号,右边第一个比它高的是7号,面积是蓝色框(遍历到7号柱时才会计算面积)。

我们额外用一个栈来存储左边第一个更高柱子 的编号(为什么是左边,因为用for循环遍历是从左边开始的,左边代表遍历过了的信息)。

右边第一个更高 的柱子会出现在for循环遍历时,见下面的case 3。

在用for循环遍历每一跟柱子时,会出现以下三种情况,我们要根据不同情况来选择如何操作栈。

  • case 1:当前遍历的元素(柱子)高度小于栈顶元素的高度 height[i] < height[st.top()]

  • case 2:当前遍历的元素(柱子)高度等于栈顶元素的高度 height[i] == height[st.top()]

  • case 3:当前遍历的元素(柱子)高度大于栈顶元素的高度 height[i] > height[st.top()] (碰到了右边第一个更高的柱子)

    int trap(vector<int> &height)
    {
        int ans{0};
        stack<int> stk; // 单调递增栈
    
    
        for (int i = 0; i < height.size(); ++i)
        {
            while (!stk.empty() && height[i] > height[stk.top()]) // case 3
            {
                int right = i;
                int mid = stk.top();
                stk.pop();
                if (!stk.empty())
                {
                    int left = stk.top(); // 弹出mid后,栈顶元素就是mid左侧第一个比它高的柱子
                    // 计算面积
                    int width = right - left - 1;
                    int h = min(height[left], height[right]) - height[mid];
                    ans += width * h;
                }
            }
            // case 1&2
            stk.push(i);
        }
        return ans;
    }
    

84. 柱状图中最大的矩形

42. 接雨水 是找每个柱子左右两边第一个大于该柱子高度的柱子,而本题是找每个柱子左右两边第一个小于 该柱子的柱子。

因此与接雨水相反,该题使用单调递增栈。

如下图,在2号柱(value: 5)柱左边第一个更小的柱子是1号柱(value: 1),右边第一个更小的柱子是4号柱(value: 2)。意味着以5为高度能贯穿两个边界这之间的柱子。

    int largestRectangleArea(vector<int> &heights)
    {
        stack<int> stk; // 单调递减栈
        int ans{0};
        heights.insert(heights.begin(), 0);  // 数组头部加入元素0
        heights.push_back(0);  // 数组尾部加入元素0
        for (int i = 0; i < heights.size(); ++i)
        {
            while (!stk.empty() && heights[i] < heights[stk.top()])
            {
                int right = i;
                int mid = stk.top();
                stk.pop();

                int left = stk.top();
                int width = right - left - 1;
                int h = heights[mid];
                ans = max(ans, width * h);
            }
            stk.push(i);
        }
        return ans;
    }
内容
  • 一文揭秘DDD到底解决了什么问题
    一文揭秘DDD到底解决了什么问题
    2023-12-01
    DDD作为架构设计思想帮助微服务控制规模复杂度,那它是怎么做到的呢?.一、架构设计是为了解决系统复杂度.谈到架构,相信每
  • Unity实现3D物体遮挡血条
    Unity实现3D物体遮挡血条
    2023-12-08
    Unity 实现3D物体遮挡血条.######.前言:在游戏开发中,我们经常会遇到UI和3D物体的层级遮挡问题,最常见的
  • 一个公式让你35岁以后能越过越好!大神修炼心法
    一个公式让你35岁以后能越过越好
    2023-12-08
    前言.Cocos 的老铁,如果你这几天没有被麒麟子给卷到?那说明你还没有真正进入 Cocos 圈子里来。为什么这么说呢?
  • C++学习-static
    C++学习-static
    2023-12-02
    全局变量使用:.作用是限定全局变量的作用范围,只能在当前文件使用,类似给它加了个private属性。.其他文件即使使用e
  • 【Oculus Interaction SDK】(五)设置不同的抓握手势
    【Oculus Interact
    2023-12-10
    前言.前段时间 Oculus 的 SDK.频繁更新,很多已有的教程都不再适用于现在的版本了。本系列文章的主要目的是记录现
  • 吃透单调栈(2)——解两道Hard题:接雨水、柱状图中最大的矩形问题
    吃透单调栈(2)——解两道Har
    2023-12-04
    怎么想到要用单调栈的?.这类题目的数据通常是一维数组,要寻找任一个元素的右边或者左边第一个 比自己大 或者小 的元素的位