当青训营遇上码上掘金
当我看到主题四我乐了,这不就是LeetCode经典的接雨水问题么hh。本文介绍三种常用的解法,抛砖引玉,更多解法可以去看这篇文章:详细通俗的思路分析,多解法,接雨水问题还是值得好好推敲的。
题干
主题 4:攒青豆
现有 n 个宽度为 1 的柱子,给出 n 个非负整数依次表示柱子的高度,排列后如下图所示,此时均匀从上空向下撒青豆,计算按此排列的柱子能接住多少青豆。(不考虑边角堆积)
以下为上图例子的解析:
输入:height = [5,0,2,1,4,0,1,0,3]
输出:17
解析:上面是由数组 [5,0,2,1,4,0,1,0,3] 表示的柱子高度,在这种情况下,可以接 17 个单位的青豆。
解法一:暴力
遇到一道题我们首先可以尝试暴力解,这通常是思考的起点。
对于本题来说,要求出所有青豆的数量,可以先计算每行青豆的数量,然后进行累加。参考代码如下:
复杂度分析
时间复杂度:O(n*m),取决于行数及最大高度
空间复杂度:O(1),不需要额外的存储空间
同样,我们可以按列来求,先计算出每列能接多少青豆,再进行累加。这样的时间复杂度为:O(n*2)
解法二:动态规划
对于解法一,数据量小时可以轻松通过,但当数据量过大将会不可避免地超时。因此必须考虑其他解法。
在这里,我们可以考虑空间换时间的方式,先从左到右遍历数组,记录左边最高的墙;再从右到左遍历数组,记录右边最高的墙。之后再从左到右遍历一次数组,根据当前位置左边最高的墙与右边最高的墙,按照短板理论,计算出当前列能接到的最大数量青豆。
这种解法其实就是按列求时的优化,参考代码如下:
复杂度分析
时间复杂度:O(n)
空间复杂度:O(n),需要记录每列左边和右边最高的墙
解法三:动态规划优化
对于解法二,可以发现其实只要记录右边最高的墙,之后在计算阶段记录左边最高的墙就可以了,这样可以少一次循环。参考代码如下:(这次用js写)
复杂度分析
时间复杂度:O(n)
空间复杂度:O(n),需要记录每列左边和右边最高的墙
总结
接雨水是一道非常好的题目,有多种解法,也有很多优化空间,本文所列举的解法并不是最优,空间复杂度可优化。借助本题可以收获一系列算法思路,感受到算法的乐趣。