当青训营遇上码上掘金。
选题为主题4:攒青豆。
题目介绍
以下为上图例子的解析:
输入: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。
解题思路
- 对于“接雨水”题型,可以考虑水平计数,也可以考虑竖直计数。我采用竖直计数,即按列计算。
- 首先考虑输入有多少列。若列数<=2,则可以返回0,没有空间用来装豆子;否则,继续计算。
- 第一列与最后一列可以忽略,因为这两列不可能有空间去装豆子,计算区间实际在1~n-2(n为height数组长度)。要计算单列空余空间,首先要确定该列左侧的最高墙和该列右侧的最高墙。两面墙取短板,则能计算该列的豆子数量。问题的关键,就在于左侧高墙与右侧高墙的确定。
- 左侧高墙,可以在列遍历计算的过程中确定。因此需要提前确定右侧高墙,可新建与height等长的数组,从n-2开始,从后往前遍历,直到i=1。新建数组的i位置存储height[i]右侧的最高墙,确定高墙的过程主要是比较两数组的i+1位置。
- 取两侧高墙的短板,减去当前位置,若差值>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
}