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

90 阅读1分钟

当青训营遇上码上掘金。

选题为主题4:攒青豆。

题目介绍

image.png

以下为上图例子的解析:

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

分析

  • 题目基本等同于“接雨水”。
  • 输入为一维数组,长度未知,理想格式为非零整型。可能会输入浮点数,但只要为正数,就不影响运行。所以在数组输入后,必须检查输入数组中是否有负数。若是将负数理解成挖洞,那么负数也不影响运行。本次解答暂不考虑输入合法问题。
  • 输出为一个数字,给定格式为整数。若输入为整型数组,那么结果为整型。若输入为浮点数数组,那么结果为浮点数。不管是浮点数,还是整型,并不影响逻辑。因此代码使用整型输入与整型输出。
  • 青豆单位即为1×1的方块。如例子所示,黑色柱子间盛下的青豆面积为17单位,输出为17。

解题思路

  1. 对于“接雨水”题型,可以考虑水平计数,也可以考虑竖直计数。我采用竖直计数,即按列计算。
  2. 首先考虑输入有多少列。若列数<=2,则可以返回0,没有空间用来装豆子;否则,继续计算。
  3. 第一列与最后一列可以忽略,因为这两列不可能有空间去装豆子,计算区间实际在1~n-2(n为height数组长度)。要计算单列空余空间,首先要确定该列左侧的最高墙和该列右侧的最高墙。两面墙取短板,则能计算该列的豆子数量。问题的关键,就在于左侧高墙与右侧高墙的确定。
  4. 左侧高墙,可以在列遍历计算的过程中确定。因此需要提前确定右侧高墙,可新建与height等长的数组,从n-2开始,从后往前遍历,直到i=1。新建数组的i位置存储height[i]右侧的最高墙,确定高墙的过程主要是比较两数组的i+1位置。
  5. 取两侧高墙的短板,减去当前位置,若差值>0,则累加至最终结果。若差值<0,则i位置为更高的墙体,该位置不可能盛豆子,也不可能盛负数豆子,忽略。

代码

func area_qingdou(height []int) (num int) {
	n := len(height)
	if n < 3 {
		return
	}
	max_left := 0
	max_right := make([]int, n)
	for i := n - 2; i >= 1; i-- {
		if max_right[i+1] > height[i+1] {
			max_right[i] = max_right[i+1]
		} else {
			max_right[i] = height[i+1]
		}
	}
	for i := 1; i <= n-2; i++ {
		// 坐标i左边最高的墙
		if max_left < height[i-1] {
			max_left = height[i-1]
		}
		// 确定左右墙的短板
		min := 0
		if max_left < max_right[i] {
			min = max_left - height[i]
		} else {
			min = max_right[i] - height[i]
		}
		if min > 0 {
			num += min
		}
	}
	return
}