高频面试算法题 - 04 接雨水

107 阅读1分钟

面试算法题-接雨水

题目:

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

rainwatertrap.png

输入:height = [0,1,0,2,1,0,1,3,2,1,2,1]
输出:6

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

示例 2:

输入:height = [4,2,0,3,2,5]

输出:9

  提示:

n == height.length
0 <= n <= 3 * 104
0 <= height[i] <= 105

接雨水问题应该是面试中较为经典且有难度的题目,面对这种题目,一般的方法就是先记住解题方法,再尝试理解

思路:

1、不要尝试去计算区域可容水量,只算每个刻度上面的水量,最后将每个刻度上的水量相加即可容水量会更加直观
2、如果需要算出每个刻度上可容水量,需要算出此刻度左右两边最高位置最后求 min(max(left),max(right)),因为可容水量取决于小的那个
3、使用 leftright 双指针来算出每个刻度左边和右边最高位置,避免每个刻度都对左右进行一次扫描,增加时间复杂度

代码:

 /**
     * 双指针方法
     * left,right 两边,哪边的 max 小,先算哪边的水量
     * @param arr
     * @return
     */
     
    public static int trap(int[] arr){
        if(arr == null || arr.length <2){
            return 0;
        }
        int N = arr.length;
        int L = 1;
        int leftMax = arr[0];
        int R = N - 2;
        int rightMax = arr[N - 1];
        int water = 0;
        // 当左右部分相碰,所有的的水量结算结束
        while(L <= R){
            if (leftMax <= rightMax){
                water += Math.max(0,leftMax - arr[L]);
                leftMax = Math.max(leftMax,arr[L++]);
            }else {
                water += Math.max(0,rightMax - arr[R]);
                rightMax = Math.max(rightMax,arr[R--]);
            }
        }
        return water;
    }