青训营主题创作活动|攒青豆

74 阅读2分钟

当青训营遇上码上掘金

1 问题重现

青训营主题创作活动中有如下问题:

主题4 攒青豆

现有 n 个宽度为 1 的柱子,给出 n 个非负整数依次表示柱子的高度,排列后如下图所示,此时均匀从上空向下撒青豆,计算按此排列的柱子能接住多少青豆。(不考虑边角堆积)

给出一个例子如图所示:

这个例子的输入为

5 0 2 1 4 0 1 0 3

输出为17

2 问题分析

(题外话:这道题让我们想到了心心念念的青豆哈)

观察此题可以得出如下规律:

  1. 整个问题可以看成多个数字组成了多个容器
  2. 一个可装青豆的容器由左边和右边组成,一个容器的最大体积为数字小的一边乘以两个边之间的距离(即容器中间的数字数量)
  3. 一个容器中的数字即为障碍,计算该容器的最大体积时要减去(即减去容器中间的数字之和)
3 解决方案

从分析中可得的规律,可总结出问题的解决逻辑如下:

  1. 划分容器
  2. 计算容器体积

让我们来依次解决提出的上述步骤:

  1. 划分容器:

    设立两个标志:左标志和右标志,分别代表容器的两边。

    第一个容器的左标志是数组的第一个数,那么右边的标志怎么找呢?

    就需要分情况讨论:

    1. 当右边有比左标志代表的数更大的数时,从左往右遍历,只要遇到一个比左标志更大的数,那么它就是右标志。计算容器体积即可
    2. 当右边没有比左标志代表的数更大的数时,利用python的max函数和index函数找出右边最大的数,此时它就是我们要找的右标志,计算容器体积即可。
  2. 计算容积体积:

    数字小的一边乘以两个边之间的距离(即容器中间的数字数量)减去容器中间的数字之和

4 代码

python3

num_string = input("height=")
num_list=num_string.split(" ")
print(num_list)
left_flag=0
left_value=int(num_list[left_flag])
right_flag=0
right_value=0
area=0
temp_area=0
deb_area=0
while True:
    if left_flag==len(num_list)-1:
        break
    max_value=int(max(num_list[left_flag+1:]))
    if max_value==0:
        break
    if max_value<=left_value:
        right_flag=num_list.index(str(max_value))
        right_value=max_value
        if right_flag-1==left_flag:
            left_flag=right_flag
            continue
        for i in num_list[left_flag+1:right_flag]:
            deb_area = deb_area + int(i)
        temp_area = right_value * (right_flag-left_flag-1) - deb_area
        area+=temp_area
        print(temp_area)
        temp_area=0
        deb_area=0
        left_flag=right_flag
        right_flag=0
        continue
    if max_value>left_value:
        right_flag=left_flag
        for i in num_list[left_flag+1:]:
            i=int(i)
            right_flag+=1
            if i >= left_value:
                right_value=i
                for j in num_list[left_flag+1:right_flag]:
                    deb_area=deb_area+j
                temp_area=left_value*(right_flag-left_flag-1)-deb_area
                area+=temp_area
                temp_area=0
                deb_area=0
                left_flag=right_flag
                right_flag=0
                break
​
print(area)