给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。

上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。 感谢 Marcos 贡献此图。

示例:

输入: [0,1,0,2,1,0,1,3,2,1,2,1]
输出: 6
【分析】:一般情况下,如果按照人的思维方式的话,要看每一个位置可以蓄多少水,我们首先会看看,左边最高的柱子有多高(这里的左边最高还包括当前这个位置的,不是真的就是在左边的最高的柱子),右边的柱子最高的有多高,然后取他们两个当中的最小值,减去当前柱子的高度,就是这个位置可以蓄的水的量了。


class Solution {
    public int trap(int[] height) {
        if(height == null || height.length == 0) return 0;
        int n = height.length;
        int tmp, res = 0;
        int maxLeft = 0, maxRight = 0;
        int[] left = new int[n];
        int[] right = new int[n];
        for(int i=0; i<n; i++){
            left[i] = maxLeft;
            maxLeft = Math.max(maxLeft, height[i]);
        }
        for(int i=n-1; i>=0; i--){
            right[i] = maxRight;
            maxRight = Math.max(maxRight, height[i]);
        }
        for(int i=0; i<n; i++){
            tmp = Math.min(left[i],right[i]);
            if(tmp >= height[i]){
                res += (tmp - height[i]);
            }
        }
        return res;
    }
}

[双指针法]:
而这个two pointer的算法就是,为什么非要把两边的最高的柱子都找出来再找短板呢?我们直接找短板不就好了。
为什么这样行得通呢?
因为你想啊,左边一个值记录到当前位置为止左边最高的柱子,右边一个值记录到当前位置为止右边最高的柱子,假设我们知道右边这个最高的柱子比左边那个最高的柱子矮,那么在当前位置,这个比较矮的右边最高柱一定是当前位置的短板,为什么呢?因为这个右边最高柱已经比那个左边最高柱矮了,那么即便两个
pointer 中间还有没有走完的位置,当前位置的长板也大于等于那个没有走完的左边最高柱了。所以我们就证明了,这个比较矮的板是当前位置的短板,然后用短板值减去当前柱子的高度就是当前位置蓄水量了。

整个vector扫一遍就是o(n)时间复杂度,左边一个pointer,右边一个pointer,还有两个值分别记录左边最高柱、右边最高柱,还有一个值记录蓄水量。所以是o(1)空间复杂度。

时间复杂度分析:o(n)


class Solution {
    public int trap(int[] height) {
        if(height == null || height.length == 0) return 0;
        int n = height.length;
        int l = 0, r = n-1;
        int res = 0;
        int maxL = 0, maxR = 0;
        while(l < r){
            maxL = Math.max(maxL, height[l]);
            maxR = Math.max(maxR, height[r]);
            if(maxL < maxR){
                res += maxL - height[l++];
            }else{
                res += maxR - height[r--];
            }
        }
        return res;
    }
}