【LeetCode】84. Largest Rectangle in Histogram【栈】

在直方图中找到面积最大的矩形的面积,第一眼看到此题就觉得和LeetCode的42题接雨水好像,最后也的确如此。原题如下

 

Given n non-negative integers representing the histogram's bar height where the width of each bar is 1, find the area of largest rectangle in the histogram.

 


Above is a histogram where width of each bar is 1, given height = [2,1,5,6,2,3].

 


The largest rectangle is shown in the shaded area, which has area = 10 unit.

 

Example: 

Input: [2,1,5,6,2,3]
Output: 10

一、栈 

       最大的矩形的高一定是直方图中的某一个竖条,宽一定是相邻的所有不低于此值的竖条的集合。问题的关键就在于界定这个集合的范围,这个集合的左边起点一定是左边最近的低于此值的竖条(或者最左边界),右终点一定是右边最近的低于此值的竖条(或者最右边界)。我们可以用一个栈来记录,当栈顶元素小于当前扫描到的竖条时,还未发现右终点,直接把竖条压入栈,于是栈中的元素是递增的(从另一个角度说递减的竖条非常简单根本用不到栈来记录),当栈顶元素大于当前扫描到竖条时,说明右终点到了,并且左起点是栈中第二个元素(因为栈中元素是递增的),宽度恰好为i-pre.top()-1,之后不断把大于当前竖条i的元素取出计算,取完后吧竖条i压入栈,继续向后扫描。

       这里出现了两个烦人的特殊情况--最左边界和最右边界,我们可以通过一些手段不必每次都判断有没有遇到边界,通过把-1先行入栈可以确保i-pre.top()-1即使在栈中没有竖条时也能计算出矩形的宽度(此时起点正好是左边界),通过给原数组末尾补0既不影响结果又解决了最后可能栈内有剩余的麻烦。优化后的代码如下:(此优化只是使代码更简洁,运行效率和优化前没有区别)

class Solution {
public:
    int largestRectangleArea(vector<int>& heights) {
        heights.push_back(0);
        stack<int> pre;
        pre.push(-1);
        int n = heights.size(),temp;
        int result = heights[0];
        for (int i = 0;i < n;i++){
            while(pre.top()!=-1 && heights[i]<heights[pre.top()]){
                temp = pre.top();
                pre.pop();
                result = max(result,heights[temp]*(i-pre.top()-1));
            }
            pre.push(i);
        }
        return result;
    }
};

也可以用数组模拟栈,思路完全一样,可以减少栈的开销,略微提升一点效率

class Solution {
public:
    int largestRectangleArea(vector<int>& height) {
    height.push_back(0); 
    int len = height.size(),res = 0, cur=1;
    int s[len+1]={0};
    s[0]=-1;
    for(int i=1;i<len;i++){
        while(cur && height[i]<height[s[cur]])
            res = max(res, height[s[cur]] * (i-s[--cur]-1));
        s[++cur]=i;
    }
    return res;
}
};

 感觉这道题还是蛮经典的,刚在牛客网也看到了它的变种,附上链接如下https://www.nowcoder.com/question/next?pid=8537283&qid=141062&tid=22238950

 

      

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值