「青训营 X 码上掘金」主题4——攒青豆

59 阅读1分钟

当青训营遇上码上掘金

题目介绍

现有 n 个宽度为 1 的柱子,给出 n 个非负整数依次表示柱子的高度,排列后如下图所示,此时均匀从上空向下撒青豆,计算按此排列的柱子能接住多少青豆。(不考虑边角堆积)

image.png

以下为上图例子的解析:

输入:height = [5,0,2,1,4,0,1,0,3]  
输出:17  
解析:上面是由数组 [5,0,2,1,4,0,1,0,3] 表示的柱子高度,在这种情况下,可以接 17 个单位的青豆。

思路分析

思路一、暴力破解

具体思路:使用双重循环,先遍历第一根柱子到最后一根柱子,再对内层的每根柱子的最左边和最右边分别进行遍历选出最大的,每一层左边最大设为leftMax,右边最大设为rightMax。再设一个累加器res,每次外循环后累加leftMax与rightMax的较小值与当前柱子高度差。

部分代码如下:

int res=0;
for(int i = 1; i < height.size()-1; i++){
    int leftMax = 0,rightMax = 0;
    for(int j = 0; j <= i; j++){
        leftMax=max(leftMax,height[j]);
    }
    for(int j = i; j < height.size(); j++){
        rightMax=max(rightMax,height[j]);
    }

    res += min(leftMax,rightMax) - height[i];

}

优缺点分析:思路简单,便于理解。时间复杂度为O(n2),效率低。

思路二、单调栈

单调栈就是比普通的栈多一个性质,即维护栈内元素单调

具体思路: 当前柱子如果小于等于栈顶元素,说明形不成凹槽,则将当前柱子入栈; 反之若当前柱子大于栈顶元素,说明形成了凹槽,于是将栈中小于当前柱子的元素pop出来。

从左到右遍历数组,遍历到当前柱子,记栈顶元素为top,下一个元素为left,根据以上规则一定存在height[top]<=height[left]。若是当前柱子height[i]>height[top],则说明形成可以攒青豆的凹槽区域,该区域的宽度为i-left-1,高度为height[left]与height[i]的较小值同栈顶height[top]的差值。根据宽度高度即可计算每一次循环中卡出的凹槽区域,将凹槽的大小累加到结果ans中

优缺点分析:时间复杂度低O(n),但栈的思想比较难以想到

代码展示

Go语言实现的单调栈代码,上传至码上掘金供参考。如有疏漏和不足,欢迎大家纠正!