LeetCode 42 接雨水

Posted ambassdor

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode 42 接雨水相关的知识,希望对你有一定的参考价值。

题目

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

上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。
技术图片

法一(按列动态规划)

首先容易想到的是遍历数组一列一列求的方法,简单来说就是在遍历时求出每一列左右两个最大高度,取小者和所在列的高度比较(若大于所在列高度,为凹字型,可接水;反之为凸字型,不可接)
但是在每次遍历的同时再次遍历求左右最大,复杂度较高。考虑在遍历前,利用状态转移方程先将左右情况求出。

代码

class Solution {
public:
    int trap(vector<int>& height) {
        int sum=0;
        int n=height.size();
        vector<int> Lmax(n,0);
        vector<int> Rmax(n,0);
        for(int i=0;i<n-1;i++){
            Lmax[i+1]=max(height[i],Lmax[i]);//左
        }
        for(int i=n-1;i>=1;i--){
            Rmax[i-1]=max(height[i],Rmax[i]);//右
        }
        for(int i=1;i<n-1;i++){
            int k=min(Lmax[i],Rmax[i])-height[i];
            if(k>0){//凹字,计算接水值
                sum+=k;
            }
        }
        return sum;
    }
};

法二(双指针)

在法一基础上取消数组Rmax和Lmax,利用左右指针节省空间。

代码

class Solution {
public:
    int trap(vector<int>& height) {
        int Lmax=0,Rmax=0,sum=0;
        int left=1,right=height.size()-2;
        if(height.size()<3)return 0;//不加过不了
        int n=1;
        while(n<=height.size()-2){//循环n-2次
            if(height[left-1]<height[right+1]){
                Lmax=max(Lmax,height[left-1]);//若左小于右,由于Lmax是由height演化而来,左侧最大一定小于右侧,直接将左侧和所在列比较
                if(Lmax>height[left])sum+=Lmax-height[left];
                left++;
            }
            else{
                Rmax=max(Rmax,height[right+1]);
                if(Rmax>height[right])sum+=Rmax-height[right];//同理,若左大于等于右,左侧最大一定大于等于右侧
                right--;
            }
            n++;
        }
        return sum;
    }
};

法三(括号法)

遍历数组,将第一个数压栈,指针next指向后一个数,比较两数大小,若height[next]>栈顶数(意味着一个右括号),弹出栈顶元素,计算接水值;若<=(左括号),压栈,直到遍历结束。

代码

class Solution {
public:
    int trap(vector<int>& height) {
        stack<int> s;
        int next=0;
        int dis,sum=0;
        while(next<height.size()){
            while(!s.empty()&&height[next]>height[s.top()]){//出现右括号
                int H=height[s.top()];//保存栈顶数,用于后面计算差值
                s.pop();//弹出左括号
                if(s.empty())break;//只有右括号无左括号情况退出
                dis=next-s.top()-1;//计算距离
                sum+=dis*(min(height[s.top()],height[next])-H);//取小者,木桶效应
            }
            s.push(next);//若next小,出现左括号,则压栈
            next++;
        }
        return sum;
    }
};

以上是关于LeetCode 42 接雨水的主要内容,如果未能解决你的问题,请参考以下文章

leetcode 每日一题 42. 接雨水

LeetCode 42 接雨水

LeetCode42题动态规划 - 接雨水

LeetCode 42. 接雨水

Leetcode 42 接雨水

[LeetCode] 42. 接雨水