矩形柱中最大的矩形(单调栈遍历一遍解决)

题目链接

题目大意

给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。

求在该柱状图中,能够勾勒出来的矩形的最大面积。
histogram.png
以上是柱状图的示例,其中每个柱子的宽度为 1,给定的高度为 [2,1,5,6,2,3]。
histogram_area.png
图中阴影部分为所能勾勒出的最大矩形面积,其面积为 10 个单位。

解题思路:

首先考虑我们怎么求出最大的矩形面积,对于每一列来说我们分别向左右延伸,直到不满足条件即出现了比当前高度小的列。这时我们所得到的图形表示包含当前位置且高度为当前位置高度的最大矩形。如上图,我们从1开始编号,对于下标为3的列它的高度为5,向左扩展,下标为2的列高度为1。向右扩展下标为5的列高度为2。所以左右下标分别为l = 2,r = 5.面积就等于(r - l - 1) * h[i]h[i]表示当前下标i所对应的高度。所以问题转化为我们对于每一块矩形怎么分别向左右找到,第一个小于当前高度的列所对应的下标。显然这是对单调栈的应用。

根据我们的思路我们需要分别求出每个矩形左边和右边的第一个小于它的下标,其实我们只需要通过单调栈一次遍历即可,因为我们是单调递减栈,即栈中的元素,它的左边都是第一个小于等于它的元素,当我们遍历数组时,遇到小于栈顶的元素,此元素就是栈顶元素右边第一个小于它的元素。即我们在栈顶元素出栈时可以得到它左右小于它的元素的下标,进而算出面积。

class Solution {
public:
  int largestRectangleArea(vector<int>& heights) {
      heights.insert(heights.begin(),-2); // 开头插入-2这样不用处理边界
      heights.push_back(-1);              //末尾插入-1,可以在最后将栈中元素全部退出
      stack<int> st;
      long long ans = 0;
      for(int i = 0 ; i < heights.size();i++){
          while(st.size() && heights[st.top()] > heights[i]){     //此处大于或者大于等于都可
              int h = heights[st.top()];    //将要退出栈的矩形高度
              int r = i;                   //右边比要退出栈的矩形高度低的下标
              st.pop();                 
              int l = st.top();             //右边比要退出栈的矩形高度低的下标
              ans =  max(ans,(r - l - 1ll) * h);
          }
          st.push(i);
      }
      return ans;
}
};

如果不能理解上面方法的可以看下面
下面是分别求出当前元素左右第一个小于该元素的下标,存在数组后再计算

class Solution {
public:
  int largestRectangleArea(vector<int>& heights) {
      heights.insert(heights.begin(),-2);
      heights.push_back(-1);
      int L[100010] = {0};
      int R[100010] = {0};
      stack<int> st;
      stack<int> st1;
      st.push(0);//先在栈中加入0,防止溢出
      for(int i = 1;i < heights.size();i++){  //求左边第一个小于该元素的下标
          while(st.size() && heights[st.top()] >= heights[i])
              st.pop();
          L[i] = st.top();
          st.push(i);
      }
      for(int i = 0;i < heights.size();i++){ 求右边第一个小于该元素的下标
          while(st1.size() && heights[st1.top()] > heights[i]){
              R[st1.top()] = i;
              st1.pop();
          }
          st1.push(i);
      }
      int ans = 0 ;
      for(int i = 1;i < heights.size() - 1;i++)
          ans = max(ans,(R[i] - L[i] - 1) * heights[i]);
      return ans;
  }
};

下面是自己输入输出的代码
题目链接

#include<cstdio>
#include<iostream>
#include<stack>
int h[20010];
using namespace std;
int main(void){
	int N;
	stack<int> st;
	cin >> N;
	h[0] = -2;
	st.push(0);
	int ans = 0;
	for(int i = 1;i <= N;i++)
		cin >> h[i];
	h[N + 1] = -1;
	for(int i = 1;i <= N + 1;i++){
		while(st.size() && h[i] < h[st.top()]){
			int r = i;
			int height = h[st.top()];
			st.pop();
			int l = st.top();
			int sqr = (r - l - 1) * height;
			ans = max(ans,sqr);
		}
		st.push(i);
	}
	cout << ans;
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值