攒青豆 | 「青训营 X 码上掘金」主题创作

110 阅读3分钟

当青训营遇上码上掘金

主题 4:攒青豆

1. 题目解读

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

image.png

以下为上图例子的解析:

输入:height = [5,0,2,1,4,0,1,0,3]
输出:17
解析:上面是由数组 [5,0,2,1,4,0,1,0,3] 表示的柱子高度,在这种情况下,可以接 17 个单位的青豆。

2. 四种青豆积攒计划——线性扫描

全得益于2022年刷了部分leetcode题目,看见攒青豆问题,脑子立马想起接雨水问题,好了,有四种方法可以接雨水,那我也有四种方法可以攒青豆。四种方法分别是:动态规划双指针线性扫描。我自己使用线性扫描AC的,原因是理解成本低,直接就可以上手写,但最为巧妙的方法,还得属栈。下面我只介绍线性扫描这一种方法,因为其余三种方法,我直接附上leetcode链接,三种解法大家自取。

算法思想:线性扫描想法很简单,直接计算每一个格子能存储的青豆数量,然后将每个格子的青豆数量累加起来,就是能积攒的所有青豆的数量啦。

算法详解:对于一个数组height,对于每个位置i,设能装的豆子数量为t,该位置左柱子的高度为l = max(height[0:i]),该位置右柱子的高度为r = max(height[i+1:]),根据短板理论,该位置最多能装的豆子数量为t = min(l, r),但由于该位置还会有墙壁高度,因此更新t = max(0, t - height[i])

算法优化:对于每个位置i,如果每次都去计算该位置的左柱子高度l和右柱子高度r,时间复杂度会变为O(nlogn),但我们发现,位置i的左柱子高度可以由位置i - 1的的左柱子高度推算出来,具体为l = max(i-1位置的左柱子高度, height[i-1]),同理,右柱子的高度为r = max(i+1位置右柱子高度, height[i+1]),如此可将时间复杂度优化到O(n)

简陋的代码

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


输入:height = [5,0,2,1,4,0,1,0,3]  
输出:17  
解析:上面是由数组 [5,0,2,1,4,0,1,0,3] 表示的柱子高度,在这种情况下,可以接 17 个单位的青豆。
"""


from typing import List
import sys


def gatherGreenBeans(height: List[int]):
  # print(height)
  n = len(height)  # the length of the height array
  l, r = [0] * (n + 1), [0] * (n + 1)  # l save the left wall's height, r save the right wall's height
  ans = 0  # record the num of the green beans we can gather

  try:
    for i in range(n):
      l[i + 1] = max(l[i], height[i])
    
    for i in range(n - 1, -1, -1):
      r[i] = max(r[i + 1], height[i])
    
    # print(l, r)
    
    for i in range(1, n):
      ans += max(min(l[i], r[i]) - height[i], 0)
    
    return ans
  except:
    return -1
  

if __name__ == "__main__":
  sys.stdin.readline()
  # print(height)
  # height = sys.stdin.readline().strip() 
  # print(height)
  height = str([5,0,2,1,4,0,1,0,3])
  height = height[1: -1]
  height = list(map(int, height.split(",")))
  ans = gatherGreenBeans(height)
  if ans == -1:
    print("Input Error")
  else:
    print(ans)