“攒青豆”解题思路

99 阅读3分钟

当青训营遇上码上掘金

本篇文章是参加「青训营 X 码上掘金」主题创作活动的文章作品,选择的主题 4 攒青豆的创作内容,下面主要介绍解题灵感与思路。

主题描述

攒青豆:现有 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 个单位的青豆。

解题思路

阅读完题目后让人很自然地想到木桶理论,也就是说由多块木板构成的木桶,决定木桶盛水量多少的关键因素是其最短的木板。只不过现实中的木桶是三维的,而我们题目中要处理问题的二维的罢了。顺着这一思路那我们下面要思考的问题无非就两个,一个是存在多少个桶的问题,另一个是如何求桶内的容积的问题,下面将分别讲解。

多少个桶的问题

通过分析我们可以看出题目中的例子应该存在两个桶,如下图所示,那么这两个桶是怎么得到的,我们可以规定这样一个方法,每次取最长的两块木板,这样能构成一个不会漏的桶,然后沿着同一方向再找两块最长的木板,就能得到另一个桶,直到所有木板都被遍历过一遍为止。

image.png

在这个问题中可能会遇到两种情况,第一种和例子中的一样,最长的木板在边缘位置,这样去寻找下一个木桶的时候只需要沿着一个方向就好了;第二种就是最长的木板不在边缘位置,这个时候需要我们将左右两个方向分别讨论,变为和第一种情况一样。

image.png

桶的容量的问题

当我们划分出桶后,计算桶的容量就非常简单了,以短板为长度计算总容量再减去其中木板所占的容量即可。

func getCapacity(columns []int) int {
  n := len(columns)
  capacity := n * columns[n-1]
  for i, v := range columns {
    if i == 0 {
      capacity -= columns[n-1]
    } else {
      capacity -= v
    }
  }
  return capacity
}

递归思路

当我们沿着一个方向去计算每个桶的容量并将它们相加的时候,明显体会到这可以是个递归过程,因此可以编写递归程序:

func resolution(columns []int) int {
  capacity := 0
  resColumns := make([]int, len(columns) - 1)
  copy(resColumns, columns[1:])
  nextHighest := highestColumn(resColumns)
  if len(columns) <= 1 {
    return capacity
  }
  capacity = getCapacity(columns[:nextHighest + 2])
  capacity += resolution(resColumns[nextHighest:])
  return capacity
}

完整代码见链接地址:code.juejin.cn/api/raw/719…