当青训营遇上码上掘金:主题 4:攒青豆

34 阅读2分钟

题目

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

攒青豆.png

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

解析

双指针 特别好理解

1.首先我们需要搞清楚,下标为i的豆量是由什么决定的. 是由i左右两边最大值中较小的那个减去height[i]决定的.例 [0,1,0,2,1,0,1,3,2,1,2,1]中,下标为2的位置 值为0,而它的用豆量是由左边的最大值1,右边最大值3 中较小的那个 也就是1减去0得到的。

2.本题解的双指针先找到当前维护的左、右最大值中较小的那个,例 当前 i 处左边的最大值如果比右边的小,那么就可以不用考虑 i 处右边最大值的影响了,因为 i 处 右边真正的最大值绝对比左边的最大值要大,在不断遍历时,更新max_l和max_r以及返回值即可。例 [0,1,0,2,1,0,1,3,2,1,2,1]中i=2时,值为0,此时max_l一定为1,当前max_r如果为2,即便max_r不是真正的i右边的最大值,也可忽略右边最大值的影响,因为右边真正的最大值一定比左边真正的最大值大。

3、利用下雨后的外轮廓线形成的数组减去原来的柱子数组,所余总和即为解。 具体方法,有两种情况 1 设当前柱子高度为x[i],搜索后面所有柱子,第一个高度大于等于当前的柱子为x[j], 那么i~j之内的柱子(不包括两端)都可以存水,且高度为x[i] 2 搜索后面柱子,若没有比当前柱子高的,当前柱子要削掉高度1,再继续搜索,直到找到高度大于当前柱子的x[j]

要削掉的原因是考虑到【5,2,3】这种情况,削掉后【4,2,3】、【3,2,3】 结果为[5, 3, 3]

class Solution {
    public int trap(int[] height) {
        int l=0;
        int r=height.length-1;
        int max_l=0;
        int max_r=0;
        int res=0;
        while(l<=r){
            if(max_l<max_r){
                if(height[l]<max_l) res+=max_l-height[l];
                else max_l=height[l];
                l++;
            }else {
                if(height[r]<max_r) res+=max_r-height[r];
                else max_r=height[r];
                r--;
            }
        }
        return res;
    }
    
}