当青训营遇上码上掘金......呃呃,好了正文开始.
题目&例
现有 n 个宽度为 1 的柱子,给出 n 个非负整数依次表示柱子的高度,排列后如下图所示,此时均匀从上空向下撒青豆,计算按此排列的柱子能接住多少青豆。(不考虑边角堆积)
- in: height = [5,0,2,1,4,0,1,0,3]
- out: 17
整体思路
每一列的青豆数取决于它的 左右最高一列的较低一列高度(顶) 和 本身的高度(底) ,公式为 . 得到了每一列的青豆数,只要求sum即可得到最终的结果.
以下两种方法都是这个思路,只是在"各自求出左右最高一列的高度"时使用了不同思路.
题解1: 中心扩散
func findHighestOne(dir, col int) int
Find the hightest one lefter/righter than the column col. "dir" control the direction, -1 is left,1 is right. The function return the height.
note: the return number >= height[col] (i.e. if nothing is bigger than height[col], the function will return itself).
func getColBeanNum(col, l, r int) int
The function return the capacity of the column by formular . The top is the lower column between the left-highest and the right-highest, while the bottum is height[col] itself.
note: if left-highest and the right-highest both are lower than height[col] itself, the top also is height[col] itself, due to the feature of findHighestOne().
package main
import (
"fmt"
)
var height []int
func main() {
height = []int{5, 0, 2, 1, 4, 0, 1, 0, 3}
allBeanNum := 0
for i := 0; i < len(height); i++ {
l := findHighestOne(-1, i)
r := findHighestOne(1, i)
colBeanNum := getColBeanNum(i, l, r)
allBeanNum += colBeanNum
}
fmt.Println(allBeanNum)
}
// find the hightest one lefter/righter than the column col.
// dir control the direction, -1 is left,1 is right.
// return the height.
// note: the return number >= heigt[col],
// i.e. if nothing is bigger than heigt[col], the function will return itself.
func findHighestOne(dir, col int) int {
highestHeight := 0
for idx := col; idx >= 0 && idx < len(height); idx += dir {
if height[idx] > highestHeight {
highestHeight = height[idx]
}
}
return highestHeight
}
// return the capacity of the column by formular `top-bottum`.
// the top is the lower column between the left-highest and the right-highest,
// the bottum is height[col] itself.
// note: if left-highest and the right-highest both are lower than height[col] itself,
// the top also is height[col] itself.
func getColBeanNum(col, l, r int) int {
top := l
if r < l {
top = r
}
btm := height[col]
return top - btm
}
题解2: 动态规划
func findHighestOne(dir, col int) int
Find the hightest one lefter/righter than the column col. "dir" control the direction, -1 is left,1 is right. The function return the height.
note: different from method1 the return number may be lower than height[col].
func getColBeanNum(col, l, r int) int
The function return the capacity of the column by formular . The top is the lower column between the left-highest and the right-highest, while the bottum is height[col] itself.
note: if the lower one between the left-highest and the right-highest is lower than height[col] itself, the result will be 0.
package main
import (
"fmt"
)
var height []int
var lmax, rmax []int
func main() {
height = []int{5, 0, 2, 1, 4, 0, 1, 0, 3}
lmax, rmax = make([]int, len(height)), make([]int, len(height))
allBeanNum := 0
for i := 1; i < len(height)-1; i++ {
findHighestOne(-1, i)
}
for i := len(height) - 2; i > 0; i-- {
findHighestOne(1, i)
}
for i := 1; i < len(height)-1; i++ {
colBeanNum := getColBeanNum(i, lmax[i], rmax[i])
allBeanNum += colBeanNum
}
fmt.Println(allBeanNum)
}
// find the hightest one lefter/righter than the column col.
// dir control the direction, -1 is left,1 is right.
// return the height.
func findHighestOne(dir, col int) (result int) {
switch dir {
case -1:
lmax[col] = max(lmax[col-1], height[col-1])
result = lmax[col]
case 1:
rmax[col] = max(rmax[col+1], height[col+1])
result = rmax[col]
}
return
}
// return the capacity of the column by formular `top-bottum`.
// the top is the lower column between the left-highest and the right-highest,
// the bottum is height[col] itself.
func getColBeanNum(col, l, r int) (result int) {
top := l
if r < l {
top = r
}
btm := height[col]
switch {
case top > btm:
result = top - btm
case top == btm:
result = 0
case top < btm:
result = 0
}
return
}
// return the bigger one
func max(a, b int) int {
if a < b {
return b
}
return a
}
总结
最后water一些大家都知道的东西.
- 方法1的时间复杂度是;如果不算原始数组的话,空间复杂度是.
- 方法2的时间复杂度是;如果不算原始数组的话,空间复杂度是.
所以各有取舍......,然我在方法二时预设了第一列和最后一列是0青豆,所以遍历的时候跳过了这俩,对于有点强迫症的我来说方法一更优雅(然并卵).