Largest Rectangle (單調棧,同POJ2559)
阿新 • • 發佈:2021-02-04
題意:
題意:給你寬度為一,高度不同的n個矩形,讓求出一個最大面積的矩形。
如下圖所示
分析:
方法一:
根據題意可知,若以h為起點,分別往兩邊找比h矮的矩形,此時比h矮的前一個組成的矩形便是能圍成的最大面積;
上述有一些意識流,看程式碼比較好理解
#include <iostream>
#include <cmath>
#include <algorithm>
#include <queue>
#include <vector>
#include <cmath>
#include <map>
#include <set>
#include <cstring>
#include <stack>
#include <string>
using namespace std;
typedef long long ll;
const int N = 1e5+199;
const double Pi = acos(-1);
ll h[N];
int l_min[N],r_min[N];
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt" ,"r",stdin);
#endif // ONLINE_JUDGE
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%lld",&h[i]);
l_min[i]=r_min[i]=i;
}
h[0]=h[n+1]=-1;
for(int i=1;i<=n;i++){//看似是n^2的複雜度,其實是O(n),有點KMP的意思
int j=i-1;
while (h[j]>=h[i])//找i的左邊比自己第一個矮的位置
j=l_min[j]-1;//這一步很重要,可以快速收斂,這樣就不是n^2的複雜度了
l_min[i]=j+1;
}
for(int i=n;i>=1;i--){
int j=i+1;
while(h[j]>=h[i])//找i的右邊比自己第一個矮的位置
j=r_min[j]+1;
r_min[i]=j-1;
}
ll ans=0;
for(int i=1;i<=n;i++){
ans=max(ans,(ll)(r_min[i]-l_min[i]+1)*h[i]);
}
printf("%lld\n",ans);
return 0;
}
方法二:單調棧
我們用棧來維護一個單調遞增的矩形高度,如果遇到一個大於等於棧頂的元素,便將其入棧,否則彈出,然後計算,直到棧頂元素小於當前的元素才再次入棧;
同樣有點意識流,還是看程式碼,最後能手動模擬一下;
#include <iostream>
#include <cmath>
#include <algorithm>
#include <queue>
#include <vector>
#include <cmath>
#include <map>
#include <set>
#include <cstring>
#include <stack>
#include <string>
using namespace std;
typedef long long ll;
const int N = 1e5+199;
const double Pi = acos(-1);
ll h[N];
int main()
{
// #ifndef ONLINE_JUDGE
// freopen("in.txt","r",stdin);
// #endif // ONLINE_JUDGE
int n;
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%lld",&h[i]);
}
h[n]=-1;//這是要用到單調棧必不可少的
int pos=0;
ll ans=0,maxval=0;
stack<int>s;//用棧來儲存下標
while(pos<=n){
if(s.empty() || h[pos]>=h[s.top()])
s.push(pos);
else{
int k;
while(!s.empty() && h[pos]<h[s.top()]){
k=s.top();
s.pop();
ans=max(ans,h[k]*(pos-k));
}
h[k]=h[pos];//這個地方需要好好理解
s.push(k);
}
pos++;
}
printf("%lld\n",ans);
return 0;
}