单调栈and单调队列

匿名 (未验证) 提交于 2019-12-02 23:52:01

单调栈

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

性质:

  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


易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!