hdu 1506(nyoj 258)Largest Rectangle in a Histogram(最大长方形(二))(单调栈)

来源:互联网 发布:5年了日本核辐射知乎 编辑:程序博客网 时间:2024/06/18 02:46

hdu题目链接:Largest Rectangle in a Histogram
nyoj题目链接:最大长方形(二)

思路一:
用三个数组记录,height[]记录高度,left[]记录当前高度延伸的最大左区间端点,right[]记录当前高度延伸的最大右区间端点。

然后通过left[]和right[]来缩短查询时间,对每一个高度形成的最大矩形面积进行比较

代码:

#include<stdio.h>#define max(a,b) (a>b?a:b)#define maxn 100000+5typedef long long LL;LL right[maxn],left[maxn],height[maxn];int main(){    LL n,cnt;    while(~scanf("%lld",&n),n)    {        for(LL i=1; i<=n; ++i)            right[i]=left[i]=i;        for(LL i=1; i<=n; ++i)            scanf("%lld",height+i);        height[0]=-1,height[n+1]=-1;        for(LL i=1; i<=n; ++i)//注意要顺序        {            cnt=i-1;            while(height[i]<=height[cnt])            {                left[i]=left[left[cnt]];//缩短查询时间                cnt=left[i]-1;            }        }        for(LL i=n; i>=1; --i)//注意要逆序        {            cnt=i+1;            while(height[i]<=height[cnt])            {                right[i]=right[right[cnt]];//缩短查询时间                cnt=right[i]+1;            }        }        LL ans=0;        for(LL i=1; i<=n; ++i)            ans=max(ans,(right[i]-left[i]+1)*height[i]);        printf("%lld\n",ans);    }    return 0;}



思路二:单调栈,看了一下午才勉强搞懂(参考博客)
它就是以某一个值为最小(最大)值,然后向这个值的两侧延伸,遇到大于它(小于它)的值,就将它延伸的范围扩大,当然,一般来说,要这样做的算法复杂度为o(n^2),但是借助栈这个玩意,维护其单调增(减),就可以在o(n)的时间复杂度解决这个问题。

将一元素加入栈时,先判断它是否大于(小于)栈顶元素,若是大于(小于)栈顶元素,加入栈,(从这里开始只讲维护单调增栈)否则,将栈顶元素出栈,直到栈顶元素小于要加入栈的元素。

在此过程中,需要维护向前延伸和向后延伸的问题,对于每一个要出栈的元素,很明显它已经不能往后延伸了,所以它的最大区间范围只能是它的左区间端点到当前位置(此时计算一下它的最大面积);
而当要加入栈的元素之前有n个栈元素出栈,那么说明这n个出栈的元素都是大于或者等于要入栈的元素,此时,我们需要维护入栈元素可以向前延伸多少个元素(相当于记录它的前面有多少个元素比它大,也就是找到它的左区间端点),所以每个栈顶元素都要向出栈了的元素延伸…..

最后,将所有元素出栈,即可将所有情况考虑。这样,就在o(n)的时间复杂度内解决了上述问题………具体详见代码

代码:

#include<stdio.h>#include<string.h>#define max(a,b) (a>b?a:b)#define maxn 100000+5typedef long long LL;LL q[maxn],left[maxn];//left记录的是从这个点开始,之前有几个高度大于等于此高度int main(){    LL n,h;    while(~scanf("%lld",&n),n)    {        for(int i=0;i<=n+1;++i)            q[i]=-1,left[i]=0;        LL top=0,ans=0;        for(LL i=1; i<=n+1; ++i)        {            if(i<=n)                scanf("%lld",&h);            else                h=0;            if(h>q[top])                q[++top]=h,left[top]=1;            else            {                LL cnt=0;                while(h<=q[top])//(前n次)每次进行此操作时,不满足单调递增的元素(在它最大区间内)的结果将计算出来                {//当循环进行到第n+1次时,单调递增栈内的每一个元素都会(在它最大的区间内)进行一次计算                    ans=max(ans,(cnt+left[top])*q[top]);                    cnt+=left[top--];                }                left[++top]=cnt+1;                q[top]=h;            }        }        printf("%lld\n",ans);    }    return 0;}
1 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 刮痧后洗了澡怎么办 刮痧后喝了啤酒怎么办 艾灸后吃水果了怎么办 刮痧后能洗澡了怎么办 膝盖筋扭了肿了怎么办 骑行之后膝盖疼怎么办 膝盖软骨磨没了怎么办 腿上膝盖长骨刺怎么办 打羽毛球后膝盖疼怎么办 打完羽毛球膝盖疼怎么办 骑动感单车后膝盖痛怎么办 踩完动感单车右膝盖痛怎么办 跑步机走步损伤膝盖怎么办 健身把膝盖伤了怎么办 膝盖后面的腿窝筋酸疼怎么办 跳绳把膝盖伤了怎么办 鼻塞嗓子肿呼吸困难怎么办 鼻子内上火肿了怎么办 鼻子又红又肿怎么办 在公司班组人员不听话怎么办 熬了一夜睡不着怎么办 有人看我脚走路怎么办 穿牛仔裤裆部有三角怎么办 我的电脑打cffps不稳定怎么办 生米煮成了熟饭该怎么办 做完下蹲腿疼该怎么办 下蹲腿的筋酸痛怎么办 躺平了 腿酸痛怎么办 500上下蹲后腿痛怎么办 蹲完马步后站不起来怎么办? 车在水里熄火了怎么办 脚磕到了很疼怎么办 破腹产4年了腰疼怎么办 蹲起之后腿疼怎么办 深蹲起跳伤腰部怎么办 蹲起膝盖有响声怎么办 腰突然不能弯了怎么办 蚂蚱吃了会过敏怎么办 孕妇能吃蚂蚱菜怎么办 孕妇吃了蚂蚁菜怎么办 白果很硬的时候怎么办