青训营×码上掘金-主题4 攒青豆

91 阅读2分钟

当青训营遇上码上掘金

这是青训营和码上掘金的联合创作活动。本文主要分析和讲解后端主题4 “攒青豆”的代码思路。

首先看题:

image.png

题意大致为,在一条直线上有若干根柱子,从直线上空均匀的洒下豆子,求这几根柱子围起来的组合体能够在柱子围成的空隙中最多留存住多少豆子(每颗豆子的体积为 1 )。

首先可以将柱子组合体的情况分类。一种比较简单的类别是两根柱子围成的空隙中没有比构成边界的这两根柱子的较小的那根更高的。另一种复杂类别是,两根柱子围成的空隙中有比这两根柱子较小的那根更高的柱子。

第一种情况的图示如下:

image.png

这两根高度为 4 和 3 的柱子中间没有高度为 3+1 或者更高的柱子。这种情况下能留住的豆子的数量可以直接通过用两根柱子中较小的那根乘以两根柱子的空隙再减去中间柱子的体积来获得。

第二种情况的图示如下:

image.png

两根高度分别为 5 和 1 的柱子中间有比 1 更高的柱子 2 。这种情况下计算起来会比较复杂。但是,我们可以发现,第二种情况可以通过拆分的方法拆解成若干个情况 1 。例如,这张图中可以拆解成 5 2 和 2 1 。但是,在这张图中,拆分会出现问题。这是因为我们不是从全局按照柱子的高度从高到低逐一去拆分的。

把这两种情况结合起来,使用分解+递归,我们可以写出这样的代码:

i = eval(input())
#i = [10, 5, 7, 2, 9, 12, 3, 4, 0, 0, 1, 0]
assert type(i) == list

def k(i):
    if len(i) <= 2: return 0
    h = min(i[0], i[-1])
    l = 0
    m = -1
    for j in range(1, len(i)-1):
        if i[j] > h:
            m = i[j]
            l = j
            pass
        pass
    if not m == -1:
        return k(i[:l+1]) + k(i[l:])
    else:
        mi = min(i[0], i[-1])
        r = mi*(len(i)-2)
        for j in i[1:-1]:
            r -= j
            pass
        return r
    pass

print(k(i))

算法代码公开在码上掘金平台

我只是算法初学萌新,如有错误还请各位不吝赐教。感谢青训营和码上掘金提供的这次机会!