240927接雨水问题

82 阅读2分钟

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

示例 1:

输入: 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
  • 1 <= n <= 2 * 104
  • 0 <= height[i] <= 105

#思路

如果知道柱子i的左右两侧最大柱子的高低差,我们就可以得出i的积水

暴力法:循环遍历i,求出左右两侧最值就可以求出解,但明显O(n^2)

如何优化左右两侧的最值呢?

如果有一个左指针,那随着右移必然可以同时更新左边的最值,此时如果右侧任意位置发现超过左边max的高度,那么就以maxleftH-height得到雨水数量;

同理如果有一个右指针,那随着左移必然可以同时更新右边的最值,如果左边任意位置发现超过右边最大高度的高柱子,那么就以maxRightH-height得到雨水数量;

最终我们结合在一起,同时用两个指针相向而行,根据两个指针遍历时候更新的左右最值,按条件至少能得到左右指针其中一个的积水数,从而做到O(N)
public int trap(int[] height) {
if (height.length < 3)
                return 0;
            int left = 1;
            int right = height.length - 2;
            int maxLeft = height[0];
            int maxRight = height[height.length - 1];
            int res = 0;

            while (left <= right) {
                //去求右指针积水
                if (maxLeft > maxRight) {
                    res += maxRight > height[right] ? maxRight - height[right] : 0;
                    maxRight = Math.max(maxRight, height[right]);
                    right--;
                } else if (maxLeft <= maxRight) {
                    res += maxLeft > height[left] ? maxLeft - height[left] : 0;
                    maxLeft = Math.max(maxLeft, height[left]);
                    left++;
                }
            }
            return res;
    }