leetcode----42.接雨水(从暴力解法优化到双指针)

42.接雨水

问题:给定 n 个非负整数表示每个宽度为 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 个单位的雨水(蓝色部分表示雨水)。 

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

思路:这道题最主要的是将问题分解,不要从全局看,而是从局部看。参考labuladong大佬题解

这道题针对局部,也就是对于位置i,能装多少水

通过观察可以发现,位置i装水的多少取决于其左边部分的最大值lMax以及其右半部分的最大值rMax 中的最小值。

于是将局部扩散到全部,可以想到一个暴力解法。对于数组中位置i,求出其左半部分以及右半部分的最大值,然后计算出当前位置i的装水量。

暴力解法的时间复杂度为O( n 2 n^2 n2),因为对于数组中的每一个位置,都需要遍历数组,寻找其左半部分以及右半部分的最大值。这个操作中包含许多重复操作。

可以使用两个备忘录提前计算好每个位置的左右部分的最大值。

  • 备忘录优化时间复杂度
class Solution {
    public int trap(int[] height) {
        int len = height.length;
        int[] lMax = new int[len], rMax = new int[len];

        lMax[0] = height[0];
        rMax[len - 1] = height[len  - 1];
        for(int i = 1; i < len; i++){
            lMax[i] = Math.max(lMax[i - 1], height[i]);
        }

        for(int i = len - 2; i >= 0; i--){
            rMax[i] = Math.max(rMax[i + 1], height[i]);
        }

        int res = 0;
        for(int i = 0; i < len; i++){
            res += Math.min(lMax[i], rMax[i]) - height[i];
        }
        return res;
    }
}
  • 双指针优化空间复杂度

备忘录的解法将时间复杂度降低到O(n),但是空间复杂度为O(n),使用双指针可以巧妙的进行优化。

下面代码中的**lMaxheight[0..left] 中最高柱子的高度,rMaxheight[right..end] 的最高柱子的高度**。虽然变量含义发生了一些变化,但是核心思想没变。

以上图为例,对于当前位置left来说,只要保证rMax >= lMax就行,即只要位置left的右半部分存在高度高于lMax的柱子,则位置left的装水量只和lMax有关。至于rMax是否为left右半部分的最大值,不重要。对于位置right同理。

class Solution {
    public int trap(int[] height) {
        int left = 0, right = height.length - 1;
        int lMax = 0, rMax = 0;

        int res = 0;
        while(left < right){
            lMax = Math.max(lMax, height[left]);
            rMax = Math.max(rMax, height[right]);

            if(lMax < rMax){
                res += lMax - height[left];
                left++;
            } else {
                res += rMax - height[right];
                right--;
            }
        }
        return res;
    }
}

整理思路,记录博客,以便复习。若有误,望指正~

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值