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

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

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

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

代码:

#include

#define max(a,b) (a>b?a:b)
#define maxn 100000+5
typedef 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
#include

#define max(a,b) (a>b?a:b)
#define maxn 100000+5
typedef 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;
}

你可能感兴趣的:(技巧题,栈/队列,ACM)