Leecode最热门的题之一
难度:困难
描述:给定 n 个非负整数表示每个宽度为 1 的柱子的高度,计算按此排列的柱子,下雨之后能接多少雨水。
示例一
输入:height=[0,1,0,2,1,0,1,3,2,1,2,1] 对应上面图中的黑色柱子分布
输出:6 蓝色部分为上面柱子应接的的雨水量
示例二
输入:height=[4,2,0,3,2,5]
输出:9
关于这个问题,网上有各种解法,比如遍历法、双指针法,都显得很专业和高深,数据结构复杂,一般不太容易看懂,这里给出一个我自己的解法,是在没有看那些方法之前独立思考出来的,所以也没有受到那些方法的干扰。不知道网上有没有人用过这种或类似的方法?
分析(以示例一为例):
从左向右看,一个柱子右边可能接水,也可能不接水,这要看这个柱子右边有没有比它低的柱子,且低的柱子右边还有没有高一点的柱子,这要考查连续三个柱子的情况,貌似很复杂。
具体分析考虑:
第一个柱子高度为0,是不能接雨水的
第二个柱子高度为1,其右边第三柱子高度为0,接了1-0=1跟第二柱子等高的一段雨水(因为右边第四个柱子的高度为2)
第四个柱子高度为2,第五柱子高度为1,因此第四个柱子右边接雨水2-1=1,单从这里看是接不住雨水的,因为其右边的柱子高度还要低一些,还好第八根柱子的高度为3
第五柱子高度为1,第六柱子高度为0,按之前的思考,第五柱子右边应该接雨水为1-0=1,但实际接雨水量为2,所以这样思考好像也行不通,没有通用性,找不出规律
试了几种思路,感觉无从下手。
最后觉得下面的操作是可行的,设原始柱子高度列表为height
- 先找出柱子中除了高度为0的柱子之外的最低的柱子高度,设其高度为m,m=min(x for x in height if x>0)。
- 找出柱子中高度大于0的柱子范围,也即找到第一个高度不为0和最后一个高度不为0的柱子的索引号min_index和max_index,并计算出范围的长度l=max_index-min_index+1。
- 然后对height的元素进行如下处理:元素为0的不作处理保持为0,元素大于0的分别减去m,这样原height列表就会变成一个新的列表,其中柱子的高度统一减去了m。在这一个高度的柱子中接了多少雨水呢?可以很方便的计算出,应该是这一层的面积l*m减去原来是柱子的面积,剩下就是雨水的面积。
- 把新生成的height列表又进行这样的处理,然后把每一层接的雨水加起来,最后就可以得到总的雨水量。
程序如下:
#函数maxindex是找出nums列表中数字大于0的元素中索引号最大的索引号
def maxindex(nums):
n=len(nums)
i=1
while i<=n:
if nums[-i]>0:
return n-i
else:
i=i+1
else:
return -1
#函数minindex是找出nums列表中数字大于0的元素中索引号最小的索引号
def minindex(nums):
for i in range(len(nums)):
if nums[i]>0:
return i
else:
return -1
#对height列表进行处理,返回每个元素减去最小项元素值的新列表和存储的雨水
def chuli(height):
new_height=[]
max_index=maxindex(height)
min_index=minindex(height)
m=min(x for x in height if x>0)
s=0
l=max_index-min_index+1
for i in height:
if i==0:
new_height.append(0)
else:
new_height.append(i-m)
s=s+m
return (new_height,l*m-s)
#检查列表元素是否都为0
def checklist(nums):
for i in nums:
if i==0:
continue
else:
return False
else:
return True
height=eval(input('pls input height='))
s=0
while not checklist(height):
x,y=chuli(height)
print(x,y)
height=x
s=s+y
print(s)
运行实例一结果:
pls input height=[0,1,0,2,1,0,1,3,2,1,2,1]
[0, 0, 0, 1, 0, 0, 0, 2, 1, 0, 1, 0] , 2
[0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0] , 4
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] , 0
6
运行实例二结果:
pls input height=[4,2,0,3,2,5]
[2, 0, 0, 1, 0, 3] , 2
[1, 0, 0, 0, 0, 2] , 3
[0, 0, 0, 0, 0, 1] , 4
[0, 0, 0, 0, 0, 0] , 0
9
总结:本解法采用对柱子按高度进行分层处理的方法,巧妙地设计出层处理模式,即以最低的柱子高度作高,以柱子所在的范围作宽度,形成一个长方形作为一层,用层面积(长方形面积)减去柱子占用面积,即可计算出每层接的雨水量,然后循环处理每层,完成总雨水量的计算,方法简便、容易理解,不涉及复杂的算法知识概念。