一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第10天,点击查看活动详情。
前言
今天在Leetcode上刷题,看到一道题很有趣。我乍一看,没有思路,但是仔细想了想,还是没思路。。。。哈哈,开个玩笑。
当我写出后解法后,系统老是提醒超出时间限制,太难了,努力想了好久,优化解法后终于通过了!还挺有成就感。
后来在官方的解法中,我又学到了其他的解题方法,解题的思路非常棒,所以就有了这篇文章,想和大家分享一下。
题目
✨描述:
给定一个数组
height,数组里有n个非负整数每个元素都表示一个宽度为 1 的柱子的高度
现在让我们来计算按此排列的柱子,下雨之后能接多少雨水。
🔋例如:
- 输入:
height = [0,1,0,2,1,0,1,3,2,1,2,1]- 输出:
6
💡解释:
- 上面的数组
[0,1,0,2,1,0,1,3,2,1,2,1]表示的是柱子的高度- 在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)
普通解法
🌱思路一
- 刚开始我的想法是,只要求出每一列上能存放的雨水量,再加起来就行
- 需要注意的是,最两端的柱子是不用考虑的,因为也不可能有雨水
- 下面举两个例子来解释一下我的思路
举例一:
由上图可知,若想求A列上的雨水,则可发现:
A两侧最高的列分别是B和C- 显然
B比C矮- 那么
A上接到的雨水量为B-A- 也就是说,
A上的雨水量为2
举例二:
由上图可知,若想求A列上的雨水,则可发现:
A两侧最高的列分别是B和C- 显然
B比C矮- 但是此时的
B比A还要矮- 那么
A上并不能接到雨水
总结:
-
我们可以对每一列上的雨水量进行计算(最两端的柱子不考虑),最后相加即可。
-
需要遍历数组,对每一列A的左右两侧
B,C中,取出较矮的那一列,减去A列的高度就能求出A上接到的雨水量(如例子一) -
但是如果
B,C较矮的那一列比A还要矮,那么A上就没有雨水。(如例子二)
🌳代码
这是刚开始我写的代码:
但是超出了时间限制:
虽然这个思路不错,但是太耗时间了,通过不了。
那怎样能减低时间复杂度?
当我们分析后发现,上述代码之所以时间复杂度高,是因为对于计算每一列上的雨水量,都必须向两边寻找最大值,这就很耗费时间。
但是,我们可以利用动态规划,先知道每个位置的两侧的最大值是多少,那么就能够更加快速的求出接到的雨水量。也就是说,提前储存每个位置上左边所有柱子中的最大值,以及右边所有柱子中的最大值。
这该如何实现呢?
思路如下:
- 我们可以定义两个数组
B和C- 当
1 <= i <= n-1时,在B[i]表示下标i及其i左边的柱子中的最大值- 正向遍历数组
height,得到B[]- 当
0 <= j <= n-2时,在C[j]表示下标j及其j右边的柱子中的最大值- 反向遍历数组
height,得到C[]- 最后遍历数组
height,对于每个柱子,计算接到的雨水值,和之前那个超时的算法差不多。
很幸运!通过了。
那么问题来了,还能想到什么解法呢?
想了很久后,思路二出现了。
🌱思路二
看下图:
- 我们先找出数组中柱子高度的最大值。
- 然后乘以数组的大小,得到了一个长方形。
- 求出这个长方形的面积后,减去白色部分和黑色部分的面积后,就可以得到雨水量!
所以整理一下思路
写出代码如下:
通过了!
其他解法
接下来,我们来欣赏一下其他超棒的解法!
🌱思路三
思路三是利用单调栈的思想。
下面是来自LeetCode官方题解:
代码实现如下:
🌱思路四
思路四是利用双指针的思想。
同样也是官方的解法。
具体如下:
写在最后
好了,对于这道题,你有什么想法呢,欢迎到评论区一起讨论,分享你的解法吧!!!