Leetcode 42-接雨水

题解

题解转载自windliang

按列求+动态规划

求每一列的水,我们只需要关注当前列,以及左边最高的墙,右边最高的墙就够了。

装水的多少,当然根据木桶效应,我们只需要看左边最高的墙和右边最高的墙中较矮的一个就够了。

所以,根据较矮的那个墙和当前列的墙的高度可以分为三种情况。

1. 较矮的墙的高度大于当前列的墙的高度
在这里插入图片描述
把正在求的列左边最高的墙和右边最高的墙确定后,然后为了方便理解,我们把无关的墙去掉。
在这里插入图片描述
这样就很清楚了,现在想象一下,往两边最高的墙之间注水。正在求的列会有多少水?

很明显,较矮的一边,也就是左边的墙的高度,减去当前列的高度就可以了,也就是 2 - 1 = 1,可以存一个单位的水。

2. 较矮的墙的高度小于当前列的墙的高度
在这里插入图片描述
同样的,我们把其他无关的列去掉。
在这里插入图片描述
想象下,往两边最高的墙之间注水。正在求的列会有多少水?

正在求的列不会有水,因为它大于了两边较矮的墙。

3. 较矮的墙的高度等于当前列的墙的高度。
和上一种情况是一样的,不会有水。
在这里插入图片描述
明白了这三种情况,程序就很好写了,遍历每一列,然后分别求出这一列两边最高的墙。找出较矮的一端,和当前列的高度比较,结果就是上边的三种情况。

首先用两个数组,max_left [i] 代表第 i 列左边最高的墙的高度,max_right[i] 代表第 i 列右边最高的墙的高度。(一定要注意下,第 i 列左(右)边最高的墙,是不包括自身的,和 leetcode 上边的讲的有些不同)

对于 max_left我们其实可以这样求。

max_left [i] = Max(max_left [i-1],height[i-1])。它前边的墙的左边的最高高度和它前边的墙的高度选一个较大的,就是当前列左边最高的墙了。

对于 max_right我们可以这样求。

max_right[i] = Max(max_right[i+1],height[i+1]) 。它后边的墙的右边的最高高度和它后边的墙的高度选一个较大的,就是当前列右边最高的墙了。

这样,我们再利用解法二的算法,就不用在 for 循环里每次重新遍历一次求 max_left 和 max_right 了。

class Solution {
    public int trap(int[] heights) {
        int len = heights.length;
        int[] max_Left = new int[len];
        int[] max_Right = new int[len];
        int sum=0;
        for(int i=1;i<len;i++){
            max_Left[i]=Math.max(heights[i-1],max_Left[i-1]);
        }
        for(int i=len-2;i>=0;i--){
            max_Right[i]=Math.max(heights[i+1],max_Right[i+1]);
        }
        for(int i=0;i<len;i++){
            int min = Math.min(max_Left[i],max_Right[i]);
            if(min>heights[i]){
                sum+=min-heights[i];
            }
        }
        return sum;
        
    }
}

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值