单调栈and单调队列

单调栈

单调栈是一种特殊的栈,特殊之处在于栈内的元素都保持一个单调性,可能为单调递增,也可能为单调递减。

性质:

  1. 单调栈里的元素具有单调性
  2. 元素加入栈前,会在栈顶端把破坏栈单调性的元素都删除
  3. 使用单调栈可以找到元素向左遍历第一个比他小的元素,也可以找到元素向左遍历第一个比他大的元素。
  4. 单调栈的维护是 O(n) 级的时间复杂度,因为所有元素只会进入栈一次,并且出栈后再也不会进栈了。

没什么好说的,直接上题

提示:点击题目直达题目提交地址

Largest Rectangle in a Histogram 

大致题意:

给定从左到右多个矩形,已知这此矩形的宽度都为1,长度不完全相等。

这些矩形相连排成一排,求在这些矩形包括的范围内能得到的面积最大的矩形,输出该面积。

所求矩形可以横跨多个矩形,但不能超出原有矩形所确定的范围。

算法分析&&具体操作:

借助单调性处理问题的思想在于及时排除不可能的选项,保持策略集合的高度有效性和秩序性

对于此题,我们需要从左向右求出每个矩形向右能够扩展到的最大连续宽度

能够扩展的条件:矩形高度大于等于当前矩形高度

那么我们求完之后算出面积取 max 即可

显然朴素算法是不行的,我们需要用到单调栈

准确的说是:

单调栈维护从起点矩形到当前矩形的高度递增序列

如果当前矩形低于于栈顶矩形,我们就一直将栈中元素弹出,直到遇到低于当前点的矩形,以此来维护栈的递增性,显然此时的点最远可以扩展到当前栈元素的位置top-1,即我们找到了当前点的扩展边界,同时把弹出的矩形合并再压入栈。

建立一个单调(递增)栈,所有元素各进栈和出栈一次。每个元素出栈的时候更新最大的矩形面积。

设栈内的矩形为一个二元组(h, w),h表示矩形的高度,w表示矩形的宽度。

如何入栈并更新呢?

① 如果当前元素比栈顶元素大或者栈为空,则直接压栈(h,1);

② 如果当前元素小于等于栈顶元素,则出栈合并矩形,直到当前元素大于栈顶元素或者栈为空时,合并矩形(h,sum_width)入栈。

③在出栈的过程中更新最大面积和累积宽度

那么重复上述①~③操作,我们可以线性O(n)求出每一组数据的解

注意事项:

单调栈要维护两个信息,一个是高度,另一个是宽度(便于计算矩形面积)

同时令H[n+1]=0,以保证所有矩形全部弹出栈 (最后没有矩形剩余在栈中)

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <algorithm>
 4 #include <string>
 5 #include <vector>
 6 #include <map>
 7 using namespace std;
 8 typedef long long LL;
 9 const int INF=0x3f3f3f3f;
10 int h[100010];//定义矩形(rectangle)高度h
11 int w[100010];//定义矩形(rectangle)宽度w
12 int stack[100010];//数组模拟矩形的高度单调栈
13 int top;
14 int n;
15 
16 void solve()//单调栈算法
17 {
18     long long ans=0;
19     for(int i=0;i<n+1;i++)//1~n+1个矩形扫描一遍
20     {
21         if(h[i]>stack[top])//如果当前矩形高于栈顶直接入栈,宽度为1(符合高度单调递增性质)
22         {
23             stack[++top]=h[i];
24             w[top]=1;
25         }
26         else//否则就持续弹出栈顶矩形合并
27         {
28             int widthsum=0;//弹出的栈顶矩形合并总宽度
29             while(stack[top]>h[i])//不满足高度单调递增继续弹出 
30             {
31                 widthsum+=w[top];//累计宽度 
32                 ans=max(ans,(long long)widthsum*stack[top]);//面积取max 
33                 top--;//弹出堆顶矩形
34             }
35             stack[++top]=h[i];//把合并好的新矩形入栈(高为H[i],宽为width+1)
36             w[top]=widthsum+1;
37         }
38     }
39     printf("%lld\n",ans);
40 }
41 
42 int main()
43 {
44     while(scanf("%d",&n)&&n)//多组数据
45     {
46         memset(h,0,sizeof(h));//初始化
47         memset(w,0,sizeof(w));
48         memset(stack,0,sizeof(stack));
49         top=0;
50         for(int i=0;i<n;i++)//读入每个矩形高度
51         {
52             scanf("%d",&h[i]);
53         }
54         solve();
55     }
56     return 0;
57 }
View Code

 下面是用了STL的代码

 1 #include<cstdio>
 2 #include<stack>
 3 #include <iostream>
 4 #include <algorithm>
 5 #include<cstring>
 6 using namespace std;
 7 inline long long read(){
 8     long long x=0,f=1;char c=getchar();
 9     while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
10     while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
11     return f*x;
12 }//很伤心呢,看错范围了,最初没改成long long 类型的,爆了几次才发现QWQ
13 struct node{
14     int h,w;
15 };//一个存高度,一个存宽度。
16 long long s[100100],ans=0;
17 int main(){
18     while(1){
19         int n=read();
20         if(n==0)return 0;
21         for(int i=1;i<=n;i++){
22             s[i]=read();
23         }
24         stack<node>st;
25         s[n+1]=0;
26         for(int i=1;i<=n+1;i++){
27             long long W=0;
28             while(!st.empty()&&s[i]<st.top().h){//单调栈!单调递增!
29                 W=W+st.top().w;
30                 ans=max(ans,W*st.top().h);
31                 st.pop();
32             }
33             st.push((node){s[i],W+1});
34         }
35         cout<<ans<<endl;
36         ans=0;
37     }
38 }
View Code

猜你喜欢

转载自www.cnblogs.com/jiamian/p/11247891.html