ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

LeetCode/柱状图中最大的矩形

2022-05-27 02:31:18  阅读:137  来源: 互联网

标签:heights right int mono stack 柱状图 矩形 LeetCode left


给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。
求在该柱状图中,能够勾勒出来的矩形的最大面积。

在遍历过程中,左边的很多信息对右边仍然有用处,不是单纯的求一个左侧最大高度或者最大面积
所以无法用动态规划来求解,而且对于每一个待考虑的矩阵,对其扩张的时候,有用的信息是其邻近的信息
而不是左右边缘的信息,同样也无法用双指针求解,先考虑暴力求解,再进行优化

1. 暴力求解

暴力求解的思路,计算所有矩形的面积,具体遍历每个位作为左边界,再往右探索该左边界的每个矩阵

class Solution {
public:
    int largestRectangleArea(vector<int>& heights) {
        int n = heights.size();
        int ans = 0;
        // 枚举左边界
        for (int left = 0; left < n; ++left) {
            int minHeight = INT_MAX;//以i为左边界的矩形只能乘以遍历过的最小高度
            // 枚举右边界
            for (int right = left; right < n; ++right) {
                // 确定高度
                minHeight = min(minHeight, heights[right]);
                // 计算面积
                ans = max(ans, (right - left + 1) * minHeight);
            }
        }
        return ans;
    }
};
左右扩张
class Solution {
public:
    int largestRectangleArea(vector<int>& heights) {
        int n = heights.size();
        int ans = 0;
        for (int mid = 0; mid < n; ++mid) {
            // 枚举高
            int height = heights[mid];
            int left = mid, right = mid;
            // 确定左右边界
            while (left - 1 >= 0 && heights[left - 1] >= height) {
                --left;
            }
            while (right + 1 < n && heights[right + 1] >= height) {
                ++right;
            }
            // 计算面积
            ans = max(ans, (right - left + 1) * height);
        }
        return ans;
    }
};

2. 单调栈

对于左右扩张的方法,本质上的问题是一维数组中对每一个数的两侧找到第一个比自己小的元素
以左侧为例,从前往后遍历的时候,如果数是降序,那每个数的左边界都是降序序列最左端,如果是升序,那每个数的左边界是左侧邻近数
这就意味着我们还要用到遍历过的信息,而且是以一种相反方向的访问方式,使用栈能很好地满足这种操作的需求
把遍历过的数放到栈里面,遍历的时候将数与栈头对比,如果是降序,即该数小于栈头,就一直出栈到该数的左边界(第一个小于它的值)
把它变成升序情况,如果是升序,左边界就是栈头,同时把数入栈,因为该信息后面还要用到
右侧遍历也是相同的原理

框架如下

        stack<int> mono_stack;//单调栈
        for (int i = 0; i < n; ++i) {
            while (!mono_stack.empty() && heights[mono_stack.top()] >= heights[i]) //注意考虑栈空情况,降(等)序出栈
                mono_stack.pop();//先出栈再赋值,因为对于降序序列一直要出栈到位升序为止才能找到左边界
            left[i] = (mono_stack.empty() ? -1 : mono_stack.top());
            mono_stack.push(i);//比较和赋值完再入栈
        }

单调栈
class Solution {
public:
    int largestRectangleArea(vector<int>& heights) {
        int n = heights.size();
        vector<int> left(n), right(n);//记录每个柱子左右,满足条件的最远下标
                                    //条件指得是第一个小于柱子高度的位置
        
        stack<int> mono_stack;//单调栈
        for (int i = 0; i < n; ++i) {//从左往右遍历找每个元素左侧满足条件最远位置

            while (!mono_stack.empty() && heights[mono_stack.top()] >= heights[i]) {
                mono_stack.pop();//如果左边这个元素大于当下节点,那他是包容右边的
                //提供了当下节点构成左边矩形区域一部分
                //所以可以不用看了,直接去掉,因为它被当下节点截断了,不会再影响后面元素
                //同时要露出我们的左边界
            }
            //如果满足增序关系,那左边界就是他前一个元素
            left[i] = (mono_stack.empty() ? -1 : mono_stack.top());
            //当下节点的左边界,即是左边第一个小于它的元素,因为大的元素全部去掉了
            mono_stack.push(i);//当下节点入栈,给后面元素继续判断
        }

        mono_stack = stack<int>();//单调栈
        for (int i = n - 1; i >= 0; --i) {
            while (!mono_stack.empty() && heights[mono_stack.top()] >= heights[i]) {
                mono_stack.pop();
            }
            right[i] = (mono_stack.empty() ? n : mono_stack.top());
            mono_stack.push(i);
        }
        
        int ans = 0;
        for (int i = 0; i < n; ++i) {
            ans = max(ans, (right[i] - left[i] - 1) * heights[i]);
        }
        return ans;
    }
};

标签:heights,right,int,mono,stack,柱状图,矩形,LeetCode,left
来源: https://www.cnblogs.com/929code/p/16316061.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有