当青训营遇上码上掘金:
题目简介
下面简要介绍一下题目“接青豆”的情况。
现有 n 个宽度为 1 的柱子,给出 n 个非负整数依次表示柱子的高度,排列后如下图所示,此时均匀从上空向下撒青豆,计算按此排列的柱子能接住多少青豆。(不考虑边角堆积)
我的思路
把列作为基本单元,那么每一列所能接的青豆取决于该列左边最高列的高度h1以及右边最高列的高度h2,那么在该列柱子加上青豆的高度便是 min(h1,h2) ,以上图中的第1列为例(列从0开始计数),其左边最高列为5,右边最高列为4,那么第一列能接的青豆数目便是 min(4,5)-0 = 4。针对特殊情况,比如最左边(或最右边)的列,可以认为其左边最高列(右边最高列)的高度为它们自身;对于数组中最大的数字,可以认为其左边最高列和右边最高列均是它自身。
那么现在的问题是如何求出每一列的左边最高列以及右边最高列。为了节省空间,建立一个长度为 n 的int型数组,用来存储 min(h1,h2)。共需遍历两遍数组,第一遍从左往右遍历,求出左边最高列h1,并记录进数组,如下图所示:
第二遍从右往左遍历,求出右边最高列h2,并把 min(h1,h2) 记录进数组。据此便可以求出接住的青豆的数目。
代码实现及介绍
实现所需功能的代码如下所示:
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
var a []int
stdin := bufio.NewReader(os.Stdin)
rs, err := stdin.ReadString('\n')
if err != nil {
fmt.Printf("An err happens:%v", err)
}
as := strings.Fields(rs)
for _, c := range as {
tmp, err := strconv.Atoi(c)
if err != nil {
continue
}
a = append(a, tmp)
}
n := len(a)
ans := make([]int, n)
mx, sum := 0, 0
for i := 0; i < n; i += 1 {
if a[i] > mx {
mx = a[i]
}
ans[i] = mx - a[i]
}
mx = 0
for i := n - 1; i >= 0; i -= 1 {
if a[i] > mx {
mx = a[i]
}
if mx-a[i] < ans[i] {
ans[i] = mx - a[i]
}
sum += ans[i]
}
fmt.Print(sum)
}
为了使得读取更加高效,使用bufio进行输入数据的读取,先将输入的数据读取到string字符串中,遇到换行符停止读取,strings.Fields可以按照空格将字符串进行分割,返回的是分割出的字符串的切片,然后利用strconv 将字符串转化为整数,两个for循环分别对应着从左到右以及从右到左的遍历,mx记录着最高高度,在for循环中实时更新。将最终结果记录在sum中进行输出。