LeetCode 高级 - 接雨水

接雨水

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

img

上面是由数组 [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

分析

观察上面的图,可以发现积水坐标 i 都满足条件

  1. height[i-1] > height[i]
  2. height[i] < height[i+1]

进一步考虑,如何处理去掉上面的两个条件之一,只需考虑单一条件。

假定已知最高点的坐标maxIndex及其高度maxValue,考虑从左逐渐靠近最高点,此时只需考虑上面的条件1,因为无论如何何时,始终有:

  • height[maxIndex] >= height[i]

即,始终右侧足够高

所以从两端向中间靠拢时,只需找局部最高curRoot即可,局部最高与其余高度值的差值和即为积水和。

对于给定例子: [0,1,0,2,1,0,1,3,2,1,2,1]:

  • 最高值为3,其坐标为7
  • 以0~6高度值为例,局部最高分别为:[0,1,1,2,2,2,2] (从左向右)
  • curRoot - height[i] 分别为 [0,0,1,0,1,2,1]
  • 于是左部分积水和为 1+1+2+1 = 5,结合图验证此结果正确。

右部分省略。

于是,只需三次遍历即可

  1. 遍历整个数组,找最高点
  2. 从左向右遍历至最高点坐标,求积水
  3. 从右向左遍历至最高点坐标,求积水

时间复杂度为O(n),以及常数空间复杂度。

代码

class Solution {
    public int trap(int[] height) {
        if(height.length<=2){
            return 0;
        }
        int maxIndex=0, maxValue = 0;
        int res = 0;
        for(int i=0;i<height.length;i++){
            if(height[i]>=maxValue){
                maxValue = height[i];
                maxIndex = i;
            }
        }

        int curRoot = height[0];
        for(int i =0;i<maxIndex;i++){
            if(curRoot<height[i]){
                curRoot = height[i];
            }else{
                res += curRoot-height[i];
            }
        }
        curRoot = height[height.length-1];
        for(int i=height.length-1;i>maxIndex;i--){
            if(curRoot<height[i]){
                curRoot = height[i];
            }else{
                res += curRoot-height[i];
            }
        }

        return res;
    }
}

猜你喜欢

转载自blog.csdn.net/whdalive/article/details/81111507