Leetcode42 接雨水(dp,单调栈,双指针)

在这里插入图片描述
本题可以有三种解法:

  • 动态规划:对每一格注水,统计每个位置高度的左边最大值和右边最大值
  • 单调栈:按照层的方式注水,使用递减单调栈寻找注水区间
  • 双指针:两个指针从左边向中间移动,一次遍对每一格子注水

动态规划:使用两个数组,分别遍历并记录每一位置左边高度的最大值,右边高度的最大值。
最后每个位置内的雨水大小 min(leftmax[i],rightmax[i]) - height[i],求和得到输出。

单调栈:栈自底向上坐标对应的高度,逐渐减小。当height[i] < stack.top()时,i 入栈;而当height[i] > stack.top()时,循环弹出栈顶元素top,计算当前栈顶元素(记为left)到i位置区间的注水量 (i-left-1) * (min(height[i],height[left])-height[top])。直到栈满足单调性质,i入栈。

双指针:指针i,j分别从数组的两端开始向中间移动,每次移动高度较小的一个,移动时给该位置注水,雨水量为min(leftmax,rightmax) - height[i/j],同按照格子注水。每个格子水量的高度由较小的高度决定,因此在移动时可以直接计算水量。

附上代码:
动态规划

class Solution {
public:
    int trap(vector<int>& height) {
        vector<int> leftmax(height.size(), 0);
        vector<int> rightmax(height.size(), 0);
        int out = 0;
        leftmax[0] = height[0];
        rightmax[height.size()-1] = height[height.size()-1];
        for(int i=1; i<height.size(); i++) leftmax[i] = max(leftmax[i-1], height[i]);
        for(int j=height.size()-2; j>=0; j--) rightmax[j] = max(rightmax[j+1], height[j]);
        for(int i=0; i<height.size(); i++) out += min(leftmax[i], rightmax[i]) - height[i];
        return out;
    }
};

单调栈

class Solution {
public:
    int trap(vector<int>& height) {
        stack<int> stk;
        int out = 0;
        for(int i=0; i<height.size(); i++){
            while(!stk.empty() && height[stk.top()] < height[i]){
                int top = stk.top();
                stk.pop();
                if(stk.empty()) break;
                int left = stk.top();
                int width =  i - left - 1;
                out += (min(height[i], height[left]) - height[top]) * width;
            }
            stk.push(i);
        }
        return out;
    }
};

双指针

class Solution {
public:
    int trap(vector<int>& height) {
        int i = 0, j = height.size()-1, out = 0;
        int leftmax = 0, rightmax = 0;
        while(i < j){
            leftmax = max(leftmax, height[i]);
            rightmax = max(rightmax, height[j]);
            if(leftmax < rightmax){
                out += leftmax - height[i];
                i++;
            } else{
                out += rightmax - height[j];
                j--;
            }
        }
        return out;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值