【每日一题】小A的柱状图

小A的柱状图

https://ac.nowcoder.com/acm/problem/23619

题目

柱状图是有一些宽度相等的矩形下端对齐以后横向排列的图形,但是小A的柱状图却不是一个规范的柱状图,它的每个矩形下端的宽度可以是不相同的一些整数,分别为 ,每个矩形的高度是 ,现在小A只想知道,在这个图形里面包含的最大矩形面积是多少。

解题思路

如果使用暴力方法,那么需要枚举宽或枚举高。

  • 如果枚举宽度,那么需要使用双重循环枚举矩形的左右边界固定宽 ,确定高度 ,求面积 。时间复杂度
  • 如果枚举高度,可以使用一重循环枚举某一根柱子,将其固定为矩形的高度 。随后从这跟柱子开始向两侧延伸,直到遇到高度小于 的柱子,就确定了矩形的左右边界(不包括边界本身)。时间复杂度

可以根据上述枚举高度的暴力方法进行优化。

先确定一根柱子,求出这根柱子左侧最近的小于其高度的柱子,即为左边界。

在遍历高度时,同时维护一个递增的单调栈。栈中存储柱子的下标和高度。

  • 如果栈为空,表示当前柱子的左边不存在比它还矮的柱子,记它的左边界为 -1。
  • 如果栈顶的元素的高度大于等于当前柱子高度,那么这个栈顶元素对于求后面柱子的左边界没有作用,故将其弹出,压入当前下标。
    这么做的原因是:从后面的柱子向左延伸时,当前柱子会将左边柱子挡住。

确定一根柱子的右边界也按照上述方法。
最后,遍历高度 ,根据其左右边界确定宽度 ,其面积为 ,更新最大面积 。返回结果。时间复杂度为

对于求柱子的右边界可以再优化一下。
当位置 被弹出栈时,说明此时遍历到的位置 的高度小于等于 ,并且在 之间没有其他高度小于等于 的柱子。所以位置 就是位置 的右边界。
这样,一遍遍历就可以求出每根柱子的左右边界。

C++代码

#include<iostream>
#include<vector>
#include<stack>
using namespace std;

int main(){
    int N;
    cin >> N;
    vector<int> p(N), h(N);
    int wide = 0;
    for(int i=0; i<N; ++i){
        cin >> p[i];
        if(i>0)
            p[i] += p[i-1];
    }
    for(int i=0; i<N; ++i)
        cin >> h[i];

    vector<int> left(N,-1), right(N,N);
    stack<int> sta;
    for(int i=0; i<N; ++i){
        while(!sta.empty() && h[sta.top()] >= h[i]){
            right[sta.top()] = i;
            sta.pop();
        }
        if(sta.empty())
            left[i] = -1;
        else
            left[i] = sta.top();
        sta.push(i);
    }

    long long ans = 0, w;
    for(int i=0; i<N; ++i){
        if(left[i]==-1)
            w = p[right[i]-1];
        else
            w = p[right[i]-1] - p[left[i]];
        ans = max(ans, h[i]*w);
    }

    cout << ans << endl;
    return 0;
}
全部评论

相关推荐

程序员花海:实习太简单了 学历可以的 实习描述应该是先介绍业务 再介绍技术 技术咋推动业务的 做到了啥收益 有没有做实验 实验组和对照组有什么不同 你最后学到了什么 有没有参与处理过线上问题 有没有参与过公司的code review 有没有参与过技术分享 这些都是可以在实习描述中写的 并且实习和项目不一样不会撞车 应该放在最前面 放在教育背景下面 另外项目有点烂大街 可以看下我主页的简历优化案例
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务