leetcode-master/problems/0042.接雨水.md

3.7 KiB
Raw Blame History

题目链接

思路

// 只要一个柱子的 // 暴力的解法 都不好写啊 // 找左面最大的, 找右边最大的,找左右边际的时候容易迷糊。我已开始还找左大于右的。 (还不够) // 每次记录单条,不要记录整个面积

暴力解法

这道题目暴力解法并不简单,我们来看一下思路。

首先要明确,要按照行来计算,还是按照列来计算。如图所示:

一些同学在实现暴力解法的时候,很容易一会按照行来计算一会按照列来计算,这样就会越写越乱。

我个人倾向于按照列来计算,比较容易理解,接下来看一下按照列如何计算。

首先,如果按照列来计算的话宽度一定是1了我们再把每一列的雨水的高度求出来就可以了。

可以看出每一列雨水的高度,取决于,该列 左侧最高的柱子和右侧最高的柱子中最矮的那个柱子的高度。

这句话可以有点绕来举一个理解例如求列4的雨水高度如图

列4 左侧最高的柱子是列3高度为2以下用lHeight表示

列4 右侧最高的柱子是列7高度为3以下用rHeight表示

列4 柱子的高度为1以下用height表示

那么列4的雨水高度为 列3和列7的高度最小值减列4高度 min(lHeight, rHeight) - height。

列4的雨水高度求出来了宽度为1相乘就是列4的雨水体积了。

此时求出了列4的雨水体积。

一样的方法,只要从头遍历一遍所有的列,然后求出每一列雨水的体积,相加之后就是总雨水的体积了。

首先从头遍历所有的列,并且要注意第一个柱子和最后一个柱子不接雨水,代码如下:

for (int i = 0; i < height.size(); i++) {
    // 第一个柱子和最后一个柱子不接雨水
    if (i == 0 || i == height.size() - 1) continue;
}

在for循环中求左右两边最高柱子代码如下

int rHeight = height[i]; // 记录右边柱子的最高高度
int lHeight = height[i]; // 记录左边柱子的最高高度
for (int r = i + 1; r < height.size(); r++) {
    if (height[r] > rHeight) rHeight = height[r];
}
for (int l = i - 1; l >= 0; l--) {
    if (height[l] > lHeight) lHeight = height[l];
}

最后,计算该列的雨水高度,代码如下:

int h = min(lHeight, rHeight) - height[i];
if (h > 0) sum += h; // 注意只有h大于零的时候在统计到总和中

整体代码如下:

class Solution {
public:
    int trap(vector<int>& height) {
        int sum = 0;
        for (int i = 0; i < height.size(); i++) {
            // 第一个柱子和最后一个柱子不接雨水
            if (i == 0 || i == height.size() - 1) continue;

            int rHeight = height[i]; // 记录右边柱子的最高高度
            int lHeight = height[i]; // 记录左边柱子的最高高度
            for (int r = i + 1; r < height.size(); r++) {
                if (height[r] > rHeight) rHeight = height[r];
            }
            for (int l = i - 1; l >= 0; l--) {
                if (height[l] > lHeight) lHeight = height[l];
            }
            int h = min(lHeight, rHeight) - height[i];
            if (h > 0) sum += h;
        }
        return sum;
    }
};

因为每次遍历列的时候还要向两边寻找最高的列所以时间复杂度为O(n^2)。 空间复杂度为O(1)。

单调栈

单调栈究竟如何做呢,得画一个图,不太好理解

按照列来算的,遇到相同的怎么办。