当青训营遇上码上掘金
题目:
现有 n 个宽度为 1 的柱子,给出 n 个非负整数依次表示柱子的高度,排列后如下图所示,此时均匀从上空向下撒青豆,计算按此排列的柱子能接住多少青豆。(不考虑边角堆积)
以下为上图例子的解析:
输入:height = [5,0,2,1,4,0,1,0,3]
输出:17
解析:上面是由数组 [5,0,2,1,4,0,1,0,3] 表示的柱子高度,在这种情况下,可以接 17 个单位的青豆。
思路分析:
第一种情况:
当list仅包含一种数字,或list长度小于3
如图所示,height = [2,2,2],list中仅包含数字2,此情况不能接到青豆。
当柱子高度相同时,不能提供容纳青豆的凹槽,不能接到青豆。同样,当list长度小于3时,柱子不可能提供能容纳青豆的凹槽,故也不能接到青豆。
我们把上述语句转化为代码:
if len(height) < 3 or len(set(height)) == 1:
area = 0
第二种情况:
中间低两侧高
当两侧柱子比中间柱子高时会产生储存青豆的凹槽。图中 height = [2,1,3],柱子能接到1个单位的青豆。
由此可见,接到青豆单位多少取决于较低一侧的柱子高度。
为了计算能接到的青豆单位,我们需要对左侧和右侧凹槽做一个统计。用题目所给的图作为例子,我们首先计算左侧柱子能获得的最多青豆单位,并把它储存在一个list中:
由此我们得到左侧柱子的最多青豆单位(包括柱子)是:[5,5,5,5,5,5,5,5,5]
代码实现:
left_max = [height[0]]
left_max_height = height[0]
for i in range(1, len(height)):
left_max_height = max(height[i], left_max_height)
left_max += [left_max_height]
同样的方法计算右侧柱子能获得的最多青豆单位,储存在另一个list中:
(由于使用right_max = [right_max_height] + right_max插入元素的时间复杂度为O(n),这里用了添加到list尾部再用reverse()的方法减少时间复杂度)
由此我们得到左侧柱子的最多青豆单位(包括柱子)是:[5,4,4,4,4,3,3,3,3]
代码实现:
right_max = [height[-1]]
right_max_height = height[-1]
for i in range(1, len(height)):
right_max_height = max(height[-(i+1)], right_max_height)
right_max += [right_max_height]
right_max.reverse()
当我们把获得的左侧柱子的最多青豆单位和右侧柱子的最多青豆单位叠加在一起,并与原图做对比:
这里,我们能非常直观的看到两者中更小的值的轮廓与右侧原图的轮廓一致。
把三幅图合并在一起,我们将得到:
(黑色表示左侧柱子的最多青豆单位,蓝色为右侧右侧柱子的最多青豆单位,红色为柱子)
通过观察我们可以看到min(黑,蓝) - 红的部分就是接到的青豆单位。
我们可以在map()中使用lambda匿名函数对left_max,right_max和height做计算。
如:min(left_max[i], right_max[i]) - height[i]这行代码得到的是每一列的青豆单位,最后通过求和即可获得所有能接住的青豆单位。
我们把上面所说放在一起,得到:
total_area = sum(map(lambda a,b,c: min(a,b)-c, left_max,right_max,height))
解答:
Python解答:
def trap(height):
if len(height) < 3 or len(set(height)) == 1:
return 0
left_max = [height[0]]
right_max = [height[-1]]
left_max_height = height[0]
right_max_height = height[-1]
for i in range(1, len(height)):
left_max_height = max(height[i], left_max_height)
right_max_height = max(height[-(i+1)], right_max_height)
left_max += [left_max_height]
right_max += [right_max_height]
right_max.reverse()
return sum(map(lambda a,b,c: min(a,b)-c, left_max,right_max,height))
JavaScript解答: