42.接雨水

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

题目描述

方法 1:暴力法

思路

如果一根柱子的左右两边有比它高的柱子的话,那这根柱子的位置就可以储存雨水,所以问题可以细化成:

每根柱子所在的位置可以储存多少雨水

要求这个问题的答案,只需分别找到这根柱子左右两侧出现的最高的柱子,取两者中较短的那根,减去当前柱子的高度,就是这个位置所能储存的雨水量了。

复杂度分析

  • 时间复杂度:$O(N^2)$,N 为数组长度,遍历数组求每根柱子的位置所能储存的雨水量是 $O(N)$,对于每根柱子,要分别向左和向右遍历找出最高的柱子,时间复杂度是 $O(N)$,所以总的时间复杂度是 $O(N^2)$。

  • 空间复杂度:$O(1)$。

代码

JavaScript Code

方法 2:空间换时间

思路

在方法 1 中,我们是分别寻找每根柱子左右两侧最高的柱子,时间复杂度是 $O(N^2)$。

但其实可以用空间换时间,先遍历一遍数组,记录下每根柱子左右最高的柱子分别是哪根。

复杂度分析

  • 时间复杂度:$O(N)$,N 为数组长度,遍历一遍记录每根柱子左侧的最高柱子为 $O(N)$,遍历一遍记录每根柱子右侧的最高柱子为 $O(N)$,遍历一遍计算每根柱子位置能储存的雨水量为 $O(N)$,即 $O(3N)$,忽略常数,也就是 $O(N)$。

  • 空间复杂度:$O(N)$,N 为数组长度,使用了两个数组来记录左右侧最高柱子,空间复杂度提高到了 $O(N)$。

代码

JavaScript Code

方法 3:双指针

思路

方法 2 使用了两个数组来记录左右侧的最高柱子,实际上,我们可以改用两个指针来记录。因为在计算雨水量的时候,我们只关心左右侧最高柱子中较短的那根,具体做法如下:

  • 定义 low, high 指针分别从数组头尾开始遍历;

  • 定义 maxL, maxR 分别记录当前左右侧最高的柱子;

  • 当 low <= high 时重复:

    1. 我们只关心较低的那根柱子,如果 low 柱子低于 high 柱子:

      1. low 柱子高于 maxL,那 low 柱子储存不了雨水,不用管它,更新 maxL 为新高度;

      2. low 柱子低于 maxL,low 柱子能储水,加上储水量;

    2. 如果 high 柱子低于 low 柱子:

      1. high 柱子高于 maxR,那 high 柱子储存不了雨水,不用管它,更新 maxR 为新高度;

      2. high 柱子低于 maxR,high 柱子能储水,加上储水量;

复杂度分析

  • 时间复杂度:$O(N)$,N 为数组长度。

  • 空间复杂度:$O(1)$。

代码

JavaScript Code

Last updated

Was this helpful?