当青训营遇上码上掘金
主题 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 个单位的青豆。
题解
代码内容如下:
def save_green_beans(input_array):
# 思想:寻找每一个点(横坐标x,纵坐标y)左右最近比该点更高的点。
# 如果有,则计算:宽:左高点x1到右高点x2(x2-x1),高:左右高点中次高点与该点的差(min(y1,y2)-y)。以该点为最低点,可以填青豆的量为:等于(x2-x1)*(min(y1,y2)-y)
# 所有可以填青豆的点求和,则为总可填青豆的和
result = 0
for loc, high in enumerate(input_array):
left, left_high = find_higher_point(loc,0,input_array)
if left == -1:
continue
right, right_high = find_higher_point(loc,1,input_array)
if right == -1:
continue
result += (right-left-1) * (min(right_high, left_high)-high)
return result
# loc 表示点的横坐标
# direction = 0 表示向左, direction = 1 表示向右
# input_array 表示输入数组
# 返回值为两个,第一个代表横坐标,第二个代表高度
def find_higher_point(loc, direction, input_array):
# 如果在该点为边点,则认为没有比它更高的点
if loc == 0 or loc == len(input_array)-1:
return -1,-1
# 向左寻找
if direction == 0:
for key in range(0,loc):
if input_array[loc-key-1] >= input_array[loc]:
return loc-key-1, input_array[loc-key-1]
# 没有找到更大的
return -1,-1
# 向右寻找
if direction == 1:
for key in range(loc+1,len(input_array)):
if input_array[key] >= input_array[loc]:
return key, input_array[key]
# 没有找到更大的
return -1,-1
if __name__ == '__main__':
input_array = [5,0,2,1,4,0,1,0,3]
print("下面是示例:")
print("输入数组为[5,0,2,1,4,0,1,0,3]")
print("输出为:",save_green_beans(input_array))
# print("下面可以自由输入数组进行测试。输入示例:如果您想输入[5,0,2],则依次输入5 0 2,数字间以空格隔开即可")
# input_str = input("请输入:")
# input_array = []
# for item_str in input_str.split(" "):
# input_array.append(int(item_str))
# print("您输入的数组的结果为:",save_green_beans(input_array))
代码的输出为:
下面是示例:
输入数组为[5,0,2,1,4,0,1,0,3]
输出为: 17
代码的最后几行被注释掉了,码上掘金平台似乎没有提供命令行输入,在本地python环境可以解除注释,自定数组内容进行测试。
代码思路
首先观察图示,直观的印象和现实中凹容器盛东西很类似。
只要一个柱子左右都有比该柱子更高的柱子,该柱子与左右更高的柱子就可以形成凹容器。
该凹容器中可能包含更小的凹容器组成,且更小的凹容器可以盛的容积与大凹容器的计算面积相同。
所以可以尝试用递归的思想。
本文在发现递归的思想之后,又发现了凹容器容积的其他规律。即
寻找每一个柱子(横坐标x,纵坐标y)左右最近比该点更高的柱子。
如果有,则计算一个长方形容积:宽,左高柱子的横坐标x1到右高柱子的横坐标x2的举例,即x2-x1;高:左右两边的高柱子中较矮的柱子与该柱子的差值(min(y1,y2)-y)。
以该点为最低点,可以填青豆的量为:等于(x2-x1)*(min(y1,y2)-y)
所有可以填青豆的点求和,则为总可填青豆的和
则容积可以解构为如下图所示
本文的代码中,在以其中某一柱子为中心,向左右分别检查最邻近的更高的柱子时,使用直接依次遍历的方式。如果考虑减少运行时间,则可以考虑使用数据结构记录遍历过的结果,帮助搜索邻近的更高的柱子。