LeetCode.42. 接雨水

77 阅读2分钟

题目


image.png

思路


  • 方法1:先得到每根柱子左右两边最高的柱子,计算以每根柱子为中心所能盛水量,结果累加
  • 方法2:双指针,优化left、right数组,两边向中间遍历,实时维护最高的柱子。每次以最低柱子为目标,计算盛水量,结果累加

代码


/*
    方法一:暴力法
    思路:
    期望知道每个柱子i左右两边的最高的那根柱子
    以每根柱子为中心,计算每根柱子可盛水量,即宽 = 1,只需想办法计算高度
    一根柱子可盛水量:
        左边最高的那根柱子,右边最高的那根柱子,两者取min,就是当前柱子可盛水的高度
    可以先用 left[i],right[i] 数组记录下每个柱子i左右边的最高柱子
*/
int trap(vector<int>& a)
{
    int n = a.size();
    
    vector<int> left(n);//left[i]: [0...i-1] 最高的柱子高度
    vector<int> right(n);//right[i]: [i+1...n-1] 最高的柱子高度

    //初始化 left、right数组
    int Lmax = a[0];
    for(int i=1;i<=n-2;i++)
    {
        left[i] = Lmax;
        Lmax = max(Lmax,a[i]);
    }
    int Rmax = a[n-1];
    for(int i=n-2;i>=1;i--)
    {
        right[i] = Rmax;
        Rmax = max(Rmax,a[i]);
    }
    int ret = 0;
    for(int i=1;i<=n-2;i++)
    {
        int curRet = 1*(min(left[i],right[i])-a[i]);
        if(curRet > 0) //两边都比当前低,不能盛水
        {
            ret += curRet;
        }
    }
    return ret;
}

/*
    方法二:双指针
    思路:
    方法一空间O(n),可以用双指针遍历来优化空间消耗
    双指针,是纯遍历的任务
    左右两边,用Lmax,Rmax 分别维护从左到右,从右到左的最大值
    双指针 遍历的 i,j,就是计算i,j柱子为中心所能盛水量
    i,j负责遍历所有位置,每一根柱子都计算其能盛水量,相当于也是以宽度=1的柱子为中心计算盛水量

    每次的目的是找 i,j中更低的柱子,以它为中心计算盛水量,盛水量取决于两边最大高度,即 min(Lmax,Rmax)

    但,<官方题解>中,a[i] < a[j]时,可以保证 Lmax < Rmax,可以不需要判断 min(Lmax,Rmax),有点难理解,但是举个例子就明白了:
    根据下面代码:
        若 a[i] < a[j],此时必然 Lmax < Rmax,
        因为若 Lmax >= Rmax的话,即a[i]左边还有更高的柱子,
        那么这根"很高的柱子"会让右边指针j一直更新: j--,
        即,这个"很高的柱子"会一直触发 if(a[j] < a[i]),a[i]就是这根"很高的柱子",而不可能执行到 if(a[i] < a[j])的情况
    */
int trap(vector<int>& a)
{
    int n = a.size();
    int ret = 0;
    int Lmax = 0;
    int Rmax = 0;
    int i = 0;
    int j = n-1;
    while(i<j)
    {
        Lmax = max(Lmax,a[i]);
        Rmax = max(Rmax,a[j]);
        if(a[i] < a[j])
        {
            // ret += (Lmax-a[i]);
            ret += (min(Lmax,Rmax)-a[i]);//朴素做法
            i++;
        }
        else
        {
            // ret += (Rmax-a[j]);
            ret += (min(Rmax,Lmax)-a[j]);
            j--;
        }
    }
    return ret;
}