leetcode-84---柱状图中最大的矩形

文章讨论了一个算法问题,即在给定的柱状图中找到能够形成的最大矩形面积。初始的两种O(n^2)复杂度的解决方案超出了时间限制。文章提出了使用单调栈来优化,通过一次遍历数组求解左右边界,从而达到O(n)的时间复杂度。这种方法首先通过单调栈找到每个柱子左边比其低的最近柱子,然后找到右边的边界,最后计算面积并找到最大值。
摘要由CSDN通过智能技术生成

题目描述:

给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。

求在该柱状图中,能够勾勒出来的矩形的最大面积。

int largestRectangleArea(int* heights, int heightsSize){


}

思路引导:矩形面积=高 X 宽

很明显:我们大致有两个思路,一是以高为基准,找最大宽度,然后依次比较面积,二是以宽度为基准,找最小高度,然后依次比较面积

我们先进行两个思路的基本实现

1.以高度为基准,找宽度

int largestRectangleArea(int* heights, int heightsSize){
    int mid=0;
    int ans=0;
    for(mid=0;mid<heightsSize;mid++)
    {
        int left=mid;
        int right=mid;
        while(left-1>=0&&heights[left-1]>=heights[mid])
            left--;
        while(right+1<heightsSize&&heights[right+1]>=heights[mid])
            right++;
        ans=fmax(ans,heights[mid]*(right-left+1));
    }
    return ans;
}

2.以宽度为基准,找高度

int largestRectangleArea(int* heights, int heightsSize){
    int max=0;
    for(int i=0;i<heightsSize;i++)
        if(max<heights[i])
            max=heights[i];
    for(int j=1;j<heightsSize;j++)
    {
        int minheight=heights[j];
        for(int i=j-1;i>=0;i--)
        {
            minheight=fmin(heights[i],minheight);
            max=fmax(max,minheight*(j-i+1));
        }
    }
    return max;
}

但很遗憾:两种方法的时间复杂度均为O(n^2),超出时间限制

那么我们如何优化时间复杂度呢?将时间复杂度变为O(n)-----只遍历一遍数组

我们观察上面两种写法和思路,会发现根据高来找宽的限制条件更加有"可操作性",而根据宽度来找高枚举的情况更多(即连续不同的宽度可能有多个相同的高),会导致不必要的计算,也就是说根据高来找宽,在优先级上已经高于根据宽来找高

那么根据高来找宽的过程,即左右边界的确定,如何通过一次遍历得到?

我们再来看看边界是如何确定的,假设我们找以下标为i的柱子高度为矩形的左右边界,那么我们只要找到比heights[i]小的最靠近i的左右柱子,就能找到左右边界,而问题的关键和答案就在标红的那句话上------单调栈

---------------------------------------------------------------------------------------------------------------------------------

什么是单调栈?

浅浅的理解一下就是栈中元素按照某种单调性存储,即符合单调性就将元素进栈,反之将栈中"阻止"该元素进栈的元素去掉,然后将元素进栈,使得栈上的元素始终保持单调性

其实,仔细想一想之前我发的表达式求值问题也是运用了单调栈的性质(符号的优先级)

---------------------------------------------------------------------------------------------------------------------------------

int largestRectangleArea(int* heights, int heightsSize){
    int left[heightsSize];
    int right[heightsSize];
    int stack[heightsSize];//建立栈
    int top=-1;//栈为空
    for(int i=0;i<heightsSize;i++)//求左边界
    {
        while(top!=-1&&heights[stack[top]]>=heights[i])//栈要满足严格单调增且不为空
            top--;
        left[i]=(top==-1?-1:stack[top]);
        stack[++top]=i;
    }
    top=-1;
    for(int i=heightsSize-1;i>=0;i--)//求右边界
    {
        while(top!=-1&&heights[stack[top]]>=heights[i])
            top--;
        right[i]=(top==-1?heightsSize:stack[top]);
        stack[++top]=i;
    }
    int ans=0;
    for(int i=0;i<heightsSize;i++)//计算面积找出最大值
        ans=fmax(ans,(right[i]-left[i]-1)*heights[i]);
    return ans;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值