42. Trapping Rain Water

题目描述:给 n 个非负整数表示的柱形图,每个柱子宽度为1,计算雨后能存储多少水。如:

Given [0,1,0,2,1,0,1,3,2,1,2,1], return 6


42. Trapping Rain Water_第1张图片

分析:对每个柱子找到其左右两边最高的柱子,则这个柱子能容纳的水的体积就是min(max_left, max_right)。

方法一:对每个柱子

  1. 从左往右扫描一遍,记录其左侧柱高的最大值

  2. 从右往左扫描一遍,记录其右侧柱高的最大值

  3. 再从头到尾扫一遍,累加每个柱子可容纳的体积

三次遍历,时间复杂度O(n),空间复杂度O(n)。

class Solution {
public:
    int trap(vector& height) {
        int n = height.size();
        if (n < 3) return 0;
        
        int mxl[n] = {0}, mxr[n] = {0};           //分别记录该柱子左右两侧的最高柱子的高度。数组需要显示初始化为0,否则为随机值。
        for (int i = 1; i < n; i ++)      //l 记录从1 ~ (n - 1) ,r记录从 0 ~ (n - 2)。两个过程遍历方向相反但可在一次遍历中完成
        {
            mxl[i] = max(mxl[i - 1], height[i - 1]);         //当前柱子左侧的最高高度为前一个柱子左侧的最高高度与前一个柱子的高度的最大值
            mxr[n - 1 - i] = max(mxr[n - i], height[n - i]);            //下标为 n - 1 - i 柱子右侧的最高高度为其后一个柱子右侧的最高高度与后一个柱子的高度的最大值
        }

        int s = 0;
        for (int i = 0; i < n; i++)
        {
            int ht = min(mxl[i], mxr[i]);       
            //cout< height[i])         //若当前柱子左右两侧最高高度的最小值比当前柱子高度高,则该柱上面缺失的部分都是存水的体积
                s += ht - height[i];
        }
        return s;
    }
};

方法二

  1. 遍历一遍找到最高的柱子,该柱子将数组分为两半

  2. 处理左部分

  3. 处理右部分

三次遍历,时间复杂度O(n),空间复杂度O(1)。

class Solution {
public:
    int trap(vector& height) {
        int mx = 0;          //记录最高柱子的下标
        int n = height.size();
        for (int i = 0; i < n; i ++)
            if (height[i] > height[mx])
                mx = i;

        int w = 0;            //记录体积
        for (int i = 0, lp = 0; i < mx; i ++)        //从前往后遍历左部分,此时右侧的最高高度已确定,lp记录左侧的最高高度
        {
            if (height[i] > lp)        //如果左侧有更高的柱子,则提高标尺
                lp = height[i];
            else
                w += lp - height[i];           //较低的柱子的上面是储水的体积
        }
        for (int i = n - 1, rp = 0; i > mx; i --)          //从后往前遍历右部分,此时左侧的最高高度已确定,rp记录右侧的最高高度
        {
            if (height[i] > rp)         //如果右侧有更高的柱子,则提高标尺
                rp = height[i];
            else
                w += rp - height[i];
        }
        return w;
    }
};

方法三:用栈模拟,每个柱子高度若小于栈顶元素则压入,否则就把栈里所有小于等于当前值的元素全部弹出并计算体积。时间复杂度O(n),空间复杂度O(n)。

class Solution {
public:
    int trap(vector& height) {
        int n = height.size();
        stack> s;      //记录下标为 i
 的柱子的高度和下标 i 
        int w = 0;

        for (int i = 0; i < n; i ++)
        {
            int ht = 0;         //前一个栈顶的柱高
            while(!s.empty())
            {
                int bar = s.top().first;         //栈顶柱高
                int pos = s.top().second;    //栈顶柱下标
                w += ( min(bar, height[i]) - ht ) * (i - pos - 1);
                ht = bar;
                
                if (height[i] < bar)       //当前柱高小于栈顶元素高度,不需要进栈,上一步已计算其上面能存水体积,继续处理下一个柱子
                    break;
                else
                    s.pop();        //否则遍历处理、弹出所有比当前柱高小的栈中元素
            }
            s.push(make_pair(height[i], i));
        }
        return w;
    }
};

你可能感兴趣的:(42. Trapping Rain Water)