LeetCode---42.接雨水

42.接雨水(这道题只会暴力解,看题解拿下)

解法一:动态规划

思想:由于要得到能接的雨水总量,一定是每一个bar位置所能接的雨水的总和,而对于每一个bar而言,其能接水的量无非就是该bar左右两边的bar的最小值减去当前bar的高度,决定了这个bar的位置能接多少水。

所以暴力解就是可以对每一根bar,分别遍历其左右两边bar的最大值,并且得到左右两边最大值的最小值,再减去该bar的高度就可以得出该bar位置的接水量,得到每一根bar的接水量,最后做累加。显然这种方式的复杂度是O(N)。

而动态规划,则用两个数组分别是left_max_arr【i】和right_max_arr【i】来分别保存第i根bar的左右两边的最大值,并且在这一步中,左边的最大值是max(left_max_arr[i-1],height[i]),而右边的最大值是max(right_max_arr[i+1],height[i]),那么我们只需要给定left_max_arr[0] = height[0], right_max_arr[len-1] = height[len-1]的初始值,就可以做递推,在O(n)时间内得到做两两边的最大值数组,最后在遍历一遍原数组,进行求和操作即可。

class Solution {
public:
    int trap(vector<int>& height) {
        int ans = 0;
        int len = height.size();
        if(len<3) return 0;
        vector<int> left_max_arr(len);
        vector<int> right_max_arr(len);
        left_max_arr[0] = height[0];
        right_max_arr[len-1] = height[len-1];
        for(int i=1;i<len;i++){
            left_max_arr[i] = max(left_max_arr[i-1],height[i]);
        }
        for(int i=len-2;i>=0;i--){
            right_max_arr[i] = max(right_max_arr[i+1],height[i]);
        }
        for(int i=0;i<len;i++){
            ans += min(left_max_arr[i],right_max_arr[i])-height[i];
        }
        return ans;
    }
};

2. 双指针

双指针的写法是对动态规划解法,在空间复杂度上的优化,由于上述的动态规划解法,需要左右最大值数组来保存每个位置的左右最大值,所以需要O(n)的空间。而双指针,可以通过维护两个做左右指针,来动态的维护每个位置的相对最大值,并且通过这种方式依次记录每个位置的存水量。

class Solution {
public:
    int trap(vector<int>& height) {
        int ans = 0;
        int left = 0,right = height.size()-1;
        int maxleft = 0,maxRight = 0;
        while(left < right){
            maxleft = max(maxleft,height[left]);
            maxRight = max(maxRight,height[right]);
            if(height[left]<height[right]){
                ans += maxleft - height[left];
                ++left;
            }else{
                ans += maxRight - height[right];
                --right;
            }
        }
        return ans;
    }
};

3.单调栈

维护一个单调栈,单调栈存储的是下标,满足从栈底到栈顶的下标对应的数组 height 中的元素递减。

从左到右遍历数组,遍历到下标 i 时,如果栈内至少有两个元素,记栈顶元素为 top,top 的下面一个元素是 left,则一定有 height[left]≥height[top]。如果 height[i]>height[top],则得到一个可以接雨水的区域,该区域的宽度是 i−left−1,高度是 min(height[left],height[i])−height[top],根据宽度和高度即可计算得到该区域能接的雨水量。

为了得到 left,需要将 top 出栈。在对 top 计算能接的雨水量之后,left 变成新的 top,重复上述操作,直到栈变为空,或者栈顶下标对应的 height 中的元素大于或等于 height[i]。

在对下标 i 处计算能接的雨水量之后,将 i 入栈,继续遍历后面的下标,计算能接的雨水量。遍历结束之后即可得到能接的雨水总量。

作者:力扣官方题解
链接:https://leetcode.cn/problems/trapping-rain-water/solutions/692342/jie-yu-shui-by-leetcode-solution-tuvc/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

class Solution {
public:
    int trap(vector<int>& height) {
        int ans = 0;
        int left = 0, right = height.size() - 1;
        int leftMax = 0, rightMax = 0;
        while (left < right) {
            leftMax = max(leftMax, height[left]);
            rightMax = max(rightMax, height[right]);
            if (height[left] < height[right]) {
                ans += leftMax - height[left];
                ++left;
            } else {
                ans += rightMax - height[right];
                --right;
            }
        }
        return ans;
    }
};

作者:力扣官方题解
链接:https://leetcode.cn/problems/trapping-rain-water/solutions/692342/jie-yu-shui-by-leetcode-solution-tuvc/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值