Largest Rectangle in a Histogram
Sample Input
7 2 1 4 5 1 3 3
4 1000 1000 1000 1000
0
Sample Output
8
4000
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1506
题意:
求直方图中最大的矩形面积
思路:
有两种解法,个人感觉DP稍简单一点,单调栈不容易理解。
(一)DP
通过两次DP,找到每个的左侧和右侧比本身高的连续的位置,最后去找最大面积。第一遍,先从左到右,然后找每个数的左侧,记录下比本身高的连续的边界位置,为L。第一遍找到了全部的L。第二遍开始找每个位置的R,从右到左开始,找每个位置的右侧比本身高的连续的边界位置为R。这时每个位置的L,R都求出了。开始判断最大值。
第一遍找L。
for(int i = 2; i <= n; i++) {
int t = i;
while(t > 1 && a[t-1] >= a[i]) {
t = l[t-1];
}
l[i] = t;
}
第二遍找R.
for(int i = n-1; i >= 1; i--) {
int t = i;
while(t < n && a[t+1] >= a[i]) {
t = r[t+1];
}
r[i] = t;
}
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 100000+10;
long long a[maxn];
long long l[maxn], r[maxn];
int main()
{
int n;
while(cin >> n && n) {
for(int i = 1; i <= n; i++) {
scanf("%lld", &a[i]);
}
l[1] = 1;
r[n] = n;
for(int i = 2; i <= n; i++) {
int t = i;
while(t > 1 && a[t-1] >= a[i]) {
t = l[t-1];
}
l[i] = t;
}
for(int i = n-1; i >= 1; i--) {
int t = i;
while(t < n && a[t+1] >= a[i]) {
t = r[t+1];
}
r[i] = t;
}
long long maxx = -1;
for(int i = 1; i <= n; i++) {
long long sum = (r[i] - l[i] + 1)*a[i];
if(sum > maxx)
maxx = sum;
}
cout << maxx << endl;
}
return 0;
}
(二) 单调栈
单调栈的思想是:用一个栈来保存下标,遇到比栈中下标对应的值大的高度时,这时把这个下标进栈,保证栈中下标的高度为递增的(可以相等)。遇到比栈中下标对应值小的高度时,出栈并就计算面积(也就是栈顶元素的高度*(i-出栈后的栈顶-1),非空栈时),如果i == n时,且为空栈时这时面积为(height[栈顶] * i),和res比较,取最大值。
为了保证有结束状态,要在最后中压入一个0,height[n] = 0;
看例子比较清晰:
height=[2,1,5,6,2,3]
- 刚开始栈为空,压入下标0;当i=1时,不满足height[1] >= height[0],下标出栈,栈为空,计算面积res = height[0](1-0) = 2;
2)高度1,5,6为依次递增的,所以对应下标依次压栈;此时栈元素有(1,2,3)。当i = 4时,不满足height[4] >= height[3],所以此时栈顶元素3出栈,计算此时面积res = height[3](4-3)=6。
3)当前栈为(1,2),栈顶为2,i=4,不满足height[4] >= height[2],所以栈顶2出栈,计算此时面积res=height[2]*(4-2)=10
4)当前栈为(1),栈顶为1,i=4,满足height[4] >= height[1],所以i=4进栈,i++;栈为(1,4), i=5时,满足height[5] >= height[4],所以5进栈,栈为(1,4,5),i++;i=6,此时height[6]=0,不满足height[6] >= height[5],5出栈,计算面积res=(6-5)*height[5]=3;
5)当前栈为(1,4),栈顶为4,i=6,不满足height[6] >= height[4],所以4出栈,计算面积res=(6-4)*height[4]=4;
6)当前栈为(1),栈顶为1,i=6,不满足height[6] >= height[1],所以1出栈,此时为空栈,这次计算面积比较特殊res=height[1]n=16=6;
参考博客:https://www.cnblogs.com/love-yh/p/7182920.html
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1000005;
long long height[maxn];
int main()
{
int n;
while(cin >> n && n) {
for(int i = 0; i < n; i++){
cin>>height[i];
}
height[n] = 0;
stack<int> s;
long long maxx = 0; //这里一定要maxx = 0 否则错。。。。
long long sum = 0;
for(int i = 0; i <= n; ++i) {
if(s.empty() || (height[s.top()] <= height[i])) {
s.push(i);
}
else {
long long p = s.top();
s.pop();
if(s.empty())
sum = height[p]*i;
else
sum = height[p]*(i-s.top()-1);
if(sum >= maxx)
maxx = sum;
--i;
}
}
cout << maxx << endl;
}
return 0;
}