雨水问题(力扣)

雨水问题

解题思路主要是来自labuladong的代码小抄,小透明在这里感谢大佬

11. 盛最多水的容器

给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0)(i, height[i])

找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。

返回容器可以储存的最大水量。

**说明:**你不能倾斜容器。

思路:双指针算法

leftright 两个指针从两端向中心收缩,一边收缩一边计算 [left, right] 之间的矩形面积,取最大的面积值即是答案

注意收缩的时候 if 语句要移动较低的一边

原因:

因为矩形的高度是由 min(height[left], height[right]) 即较低的一边决定的

你如果移动较低的那一边,那条边可能会变高,使得矩形的高度变大,进而就「有可能」使得矩形的面积变大;相反,如果你去移动较高的那一边,矩形的高度是无论如何都不会变大的,所以不可能使矩形的面积变得更大。

ass Solution {
public:
    int maxArea(vector<int>& height) {
        //双指针算法
        int res = 0;
        int l = 0,r = height.size() - 1;
        while(l < r){
            res = max(res,min(height[l],height[r]) * (r - l));
            if(height[l] > height[r]) r--;
            else l ++;
        }
        return res;
    }
};

42. 接雨水

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

示例 1:

img

输入: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 个单位的雨水(蓝色部分表示雨水)。

实现思路和优化过程

我们不要想整体,而应该去想局部

具体来说,仅仅对于位置 i,能装下多少水呢?

img

能装 2 格水,因为 height[i] 的高度为 0,而这里最多能盛 2 格水,2-0=2。

为什么位置 i 最多能盛 2 格水呢?因为,位置 i 能达到的水柱高度和其左边的最高柱子、右边的最高柱子有关,我们分别称这两个柱子高度为 l_maxr_max位置 i 最大的水柱高度就是 min(l_max, r_max)

更进一步,对于位置 i,能够装的水为:

water[i] = min(
               # 左边最高的柱子
               max(height[0..i]),  
               # 右边最高的柱子
               max(height[i..end]) 
            ) - height[i]
    

暴力方法:

遍历,以i为中心,找到左边和右边最高的柱子

image-20220404141326644

优化:用备忘录优化

l_max[i],r_max[i] 记录i左右两边最大柱子的高度

双指针算法

l_maxheight[0..left] 中最高柱子的高度,r_maxheight[right..end] 的最高柱子的高度

image-20220404141649238

注意此时r_max表示的是right ->end的最大柱子高度,而不是i点到end的最大高度

为什么这样计算也没有问题?

我们只在乎 min(l_max, r_max)对于上图的情况,我们已经知道 l_max < r_max 了,至于这个 r_max 是不是右边最大的,不重要。重要的是 height[i] 能够装的水只和较低的 l_max 之差有关

如图所示

image-20220404141850351

代码实现

class Solution {
public:
    int trap(vector<int>& height) {
        int left = 0,right = height.size() - 1;
        int l_max = 0,r_max = 0;
        int res = 0;
        while(left < right){
            l_max = max(l_max,height[left]);
            r_max = max(r_max,height[right]);

            if(l_max < r_max){
                res += l_max - height[left];
                left ++;
            }else{
                res += r_max - height[right];
                right --;
            }
        }
        return res;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值