力扣hot100--接雨水

前言        

        相信不少码友都做过力扣hot100里的42. 接雨水,我个人的思路是从行的角度来看,下面我将结合图画推演和代码来简单的演示一下。

代码展示

class Solution {
public:
    int trap(vector<int>& height) {
        int n = height.size();  // 获取数组长度(柱子数量)
        if (n <= 2) return 0;  // 边界条件:少于3个柱子无法接水,直接返回0
        
        int left = 0, right = n - 1;  // 双指针:left从左向右,right从右向左
        int rain = 0;  // 存储总接水量
        
        // 跳过左侧高度为0的柱子(这些柱子无法参与储水,不是有效边界)
        while (height[left] == 0 && left < n) left++;
        // 跳过右侧高度为0的柱子(同理,不是有效边界)
        while (height[right] == 0 && right > 0) right--;
        
        // 双指针遍历,直到左右指针相遇(所有区间处理完毕)
        while (left < right) {
            // 当前区间的有效储水高度由左右边界中较矮的那个决定(短板效应)
            int h = min(height[left], height[right]);
            
            // 计算当前区间(left到right)在高度h下的总面积(假设区间内全是水)
            int s = h * (right - left + 1);
            
            // 计算区间内柱子本身占据的面积(这些部分无法储水)
            int unrain = 0;
            for (int i = left; i <= right; i++) {
                if (height[i] > h) {
                   // 柱子高度超过h,超出部分不影响储水,仅计算h高度内的柱子面积
                    unrain += h;
                } else {
                  //柱子高度低于或等于h,直接累加其高度,同时将其"补高"到h(标记已统计的雨水)
                    unrain += height[i];
                    height[i] = h;
                }
            }
            
            // 当前区间的储水量 = 总面积 - 柱子占据的面积,累加到总接水量
            rain += s - unrain;
            
            // 移动指针到下一个有效边界(寻找比当前h更高的柱子,作为新的边界)
            if (height[left] <= height[right]) {
                // 左边界较矮,移动左指针到第一个比h高的柱子(新的左边界)
                while (height[left] <= h && left < right) left++;
            } else {
                // 右边界较矮,移动右指针到第一个比h高的柱子(新的右边界)
                while (height[right] <= h && left < right) right--;
            }
        }
        
        return rain;  // 返回总接水量
    }
};

思路讲解

        看到这题,我的第一想法是定义左指针 left 和右指针 right ,从数组两端第一个非零点(0的话存不了水,所以可以直接跳过)开始遍历,每次计算左右指针能装下最大水量的面积 s,然后遍历左右指针区间,计算不能存水的面积 unrain,就可以得到该 h 行能存放的雨水 rain 。

        之后移动左右指针较小的一个,为什么不移动大的那个呢?

        其实,这题的关键就在这里,小的那边能存放的雨水已经被统计完了(比如图例第一次,第一行能存的雨水都被统计完了),而较大的那边后续可能有比它更大的(比如图例第二次,第二行的还没统计),为了避免漏算,所以要保留较大的。

        第一次时,left=1,right=11,height[left]=1,height[right]=1,高度h为1 ( min(height[left], height[right]) ),所以此时s=1*(11-1+1),unrain=9,rain=s-unrain=2。

        之后把第一行全部标记为黑,移动left,此时height[left]=0小于h,所以继续移动,此时height[left]=2,又因为height[right]=1,根据水桶效应,还是计算h=1的(已经计算过了),跳过。

移动right,此时height[left]=2,此时h=2,s=2*(10-3+1)=16,unrain=12,rain=2+(16-12)=6

        以上便是演示结果,有不当之处,还请大神指正。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值