【Leetcode】42. Trapping Rain Water

题目地址:

https://leetcode.com/problems/trapping-rain-water/

题目大意是,给定一个长 n n n数组 A A A,表示每个位置的“柱子”高度,求下雨时这些柱子能盛放的水的体积。

法1:双指针。容易知道,每个位置 i i i的正上方能盛的水的量取决于其左右最高的两个柱子的较矮者,如果这个较矮者的高度为 h h h,则 A [ i ] A[i] A[i]正上方能盛的水的量就等于 max ⁡ { 0 , h − A [ i ] } \max\{0,h-A[i]\} max{0,hA[i]}。于是我们可以从最左和最右开两个指针,同时开两个变量记录左边最高柱子高度和右边最高柱子高度,初始化为 A A A的首尾数字,然后从两边到中间依次计算每个位置的水量。具体做法请看代码注释,代码如下:

class Solution {
 public:
  int trap(vector<int>& h) {
    int res = 0;
    // maxl表示当前位置的左边的最高柱子高度,maxr表示当前位置的右边的最高柱子高度
    for (int l = 0, r = h.size() - 1, maxl = h[0], maxr = h.back(); l <= r;)
      // 如果maxl比maxr小,说明A[l + 1]的位置的左边最高就是maxl,右边最高就是maxr,则可以算出其盛水量。
      // 算完盛水量以后更新一下maxL
      if (maxl <= maxr)
        res += max(0, maxl - h[l]), maxl = max(maxl, h[l]), l++;
      else
        res += max(0, maxr - h[r]), maxr = max(maxr, h[r]), r--;
    return res;
  }
};

时间复杂度 O ( n ) O(n) O(n),空间 O ( 1 ) O(1) O(1)

法2:动态规划。容易看出来,下标为 i i i的位置的正上方能盛多少水,取决于其左右两边最高柱子的较小值减去 A [ i ] A[i] A[i]。因为下雨的时候,它左右最高柱子之间盛放的水的高度,就是两个柱子的较矮者。所以我们只需要求出每个位置的左右两边的最大值即可。设 f [ i ] f[i] f[i] A [ i ] A[i] A[i]的左边的最大值,那么 f [ i ] = max ⁡ { f [ i − 1 ] , A [ i − 1 ] } f[i]=\max\{f[i-1],A[i-1]\} f[i]=max{f[i1],A[i1]}其中 f [ 0 ] = A [ 0 ] f[0]=A[0] f[0]=A[0] A [ i ] A[i] A[i]的右边的最大值也有类似的递推公式。最后重新遍历数组,求盛放水的体积即可。代码如下:

class Solution {
 public:
  int trap(vector<int>& h) {
    int n = h.size();
    int fl[n], fr[n];
    fl[0] = h[0];
    for (int i = 1; i < n; i++) fl[i] = max(fl[i - 1], h[i - 1]);
    fr[n - 1] = h[n - 1];
    for (int i = n - 2; i >= 0; i--) fr[i] = max(fr[i + 1], h[i + 1]);

    int res = 0;
    for (int i = 1; i < n - 1; i++) res += max(0, min(fl[i], fr[i]) - h[i]);
    return res;
  }
};

时空复杂度 O ( n ) O(n) O(n)

在这里插入图片描述
法2:单调栈。与上面做法不同的是,我们这里可以考虑横着切(这里类似于勒贝格积分的做法,而上面的做法是类似黎曼积分的做法)。考虑某个柱子与其两边最近的比它高的柱子所围成的水的量(比如图中的 2 , 3 , 4 2,3,4 2,3,4组成的矩形),设某个位置 i i i处,两边离它最近且比它高的柱子分别是 A [ l ] A[l] A[l] A [ r ] A[r] A[r],那么这个矩形的长就是 r − l − 1 r-l-1 rl1,而宽就是 min ⁡ { A [ l ] , A [ r ] } − A [ i ] \min\{A[l],A[r]\}-A[i] min{A[l],A[r]}A[i]。我们可以开一个严格单调下降栈,遇到比栈顶大于等于的数的时候,就将栈顶出栈,累加一下矩形面积。代码如下:

class Solution {
 public:
  int trap(vector<int>& h) {
    int n = h.size();
    int res = 0;
    stack<int> stk;
    for (int i = 0; i < n; i++) {
      while (stk.size() && h[stk.top()] <= h[i]) {
        int tp = stk.top(); stk.pop();
        if (stk.size())
          res += (min(h[stk.top()], h[i]) - h[tp]) * (i - stk.top() - 1);
      }
      stk.push(i);
    }
    return res;
  }
};

时空复杂度 O ( n ) O(n) O(n)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值