LeetCode—42.接雨水(Trapping Rain Water)——分析及代码(C++)

一、题目

给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
在这里插入图片描述
上面是由数组 [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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/trapping-rain-water
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

二、分析及代码

1. 双指针法(初始版)

(1)思路

承接雨水的结构类似水槽,水面高度取决于左右两侧较低的木板,可以直观地联想到双指针法。
分别记录左右两侧当前已遍历的最高值,左右两侧各设置一个指针,每次选取最高值低者移动;
过程:
1)本侧最高值 >= 当前值:由于对侧一定存在更高值,当前格储水量即为 “本侧最高值 - 当前值”;
2)当前值 > 本侧最高值:当前值将成为新的水槽(不储水),将本侧最高值更新为当前值。
时间复杂度:一次遍历,O(n);
空间复杂度:O(1)。

(2)代码

class Solution {
public:
    int trap(vector<int>& height) {
        if (height.size() == 0) return 0;
        int l = 0, r = height.size() - 1;
        int lh = height[l], rh = height[r];
        int ans = 0;
        bool lmax = (lh >= rh) ? true : false;//记录当前最大值在左侧 or 右侧
        while (l < r) {
            if (lmax) {//左侧最高值更高,遍历右侧
                r--;
                if (height[r] <= rh)
                    ans += rh - height[r];
                else {
                    rh = height[r];
                    if (height[r] > lh)
                        lmax = false;
                }
            }
            else {//右侧最高值更高,遍历左侧
                l++;
                if (height[l] <= lh)
                    ans += lh - height[l];
                else {
                    lh = height[l];
                    if (height[l] > rh)
                        lmax = true;
                }
            }
        }
        return ans;
    }
};

(3)结果

执行用时 :8 ms, 在所有 C++ 提交中击败了 80.87% 的用户;
内存消耗 :9 MB, 在所有 C++ 提交中击败了 91.29% 的用户。

2. 双指针法(优化极简版)

(1)思路

进一步思考,可以直接根据指针对应值的高低选取遍历对象。

且由于每次都在左右指针中选取较低者进行遍历,所以存在以下特点:
1)未遍历部分(可具体到对侧)一定存在比已遍历部分(可具体到本侧)任意值都更高的值;
2)当且仅当指针移动后对应的新值大于已遍历的最高值时,左右指针才会更替,且对侧载入的值成为最高值(即 “本侧新值 > 对侧新值 > 原最高值” 时左右发生轮换);

因此,只需一个值记载已遍历的最大高度,无需分为左右两个值。

(2)代码

class Solution {
public:
    int trap(vector<int>& height) {
        int l = 0, r = height.size() - 1, h = 0, ans = 0;
        while (l < r)
            if (height[l] < height[r]) 
                (height[l] >= h) ? (h = height[l++]) : (ans += h - height[l++]);
            else 
                (height[r] >= h) ? (h = height[r--]) : (ans += h - height[r--]);
        return ans;
    }
};

(3)结果

执行用时 :4 ms, 在所有 C++ 提交中击败了 97.59% 的用户;
内存消耗 :9 MB, 在所有 C++ 提交中击败了 91.29% 的用户。

三、其他

暂无。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值