当青训营遇上码上掘金
这是一篇姗姗来迟的题解,当其他同学都在用C/C++解题的时候我还在努力学Go,就为了这一天能用Go解出此题,虽然语言不重要,但至少证明了努力没辜负!
首先请允许我附上题目描述:
现有 n 个宽度为 1 的柱子,给出 n 个非负整数依次表示柱子的高度,排列后如下图所示,此时均匀从上空向下撒青豆,计算按此排列的柱子能接住多少青豆。(不考虑边角堆积)
输入样例就不给了,思路到了就行。
首先这是一道很应景的题,我第一眼看到这道题的时候想到的是双循环、双指针,或者分治,当然我个人是没有学习过正统的算法,因此只能基于个人思考解题,显然并非最优解。
在我深思熟虑下不了手的时候,我猛然发现,虽然现实中豆子和墙的长宽、体积等数据无法比较,但是在程序中的单位一定是可以统一的,于是不妨将墙体横着看,分为一层一层的“新墙”,于是从底层开始分析,显然豆子的数量由每层第一个和最后一个最高的墙体决定,在分层后,这个高度就不用计数了,只有相等和更高两个概念,然后我们只需要找出最高的第一个和最后一个墙体,再依次增加层数不断动态更新青豆数量即可。
这么看来时间复杂度显然是O(n2),不能说比双指针等方式更高效,但是也好过多重循环暴力解题,此外go语言中的指针不能进行地址计算也是一个很大的制约。
那么再次附上个人代码,代码中已经注明必要的注释,这个方法曾经在某系地方见到过,可能会与部分同学雷同,此情况实属巧合,希望互相借鉴学习!
package main
import (
"fmt"
)
func maxL(height []int) int {
maxL := height[0]
for i := 1; i < len(height); i++ {
if height[i] > maxL {
maxL = height[i]
}
}
return maxL
}
func solution(height []int) int {
// 用于存储计算结果
num := 0
// 数组长度
sliceLen := len(height)
// begin 当前层第一个高出来的墙
// end 当前层最后一个高出来的墙
var begin, end = 0, sliceLen - 1
wallHeight := maxL(height) // 最高墙
//从第一层开始遍历
for i := 1; i <= wallHeight; i++ {
// 求当前层的begin和end
for begin <= end {
if height[begin] >= i {
break
}
begin++
}
for begin <= end {
if height[end] >= i {
break
}
end--
}
// 在当前层寻找可以容纳青豆的空隙
for j := begin + 1; j < end; j++ {
if height[j] < i {
num++
}
}
}
return num
}
func main() {
//切片长度
sliceLen := 0
_, err := fmt.Scanf("%d", &sliceLen)
if err != nil {
fmt.Println("No scanf")
return
}
//切片
height := make([]int, sliceLen)
for i := 0; i < sliceLen; i++ {
_, err := fmt.Scanf("%d", &height[i])
if err != nil {
fmt.Println("No scanf")
return
}
}
fmt.Println(solution(height))
}
那么简单说明一下,solution函数则是题解,maxL函数仅用于找出最高的墙体并在solution中唯一被调用,solution作为核心函数也被main函数唯一调用,时间复杂度在双重循环部分被拉高,目前没有更好的办法。
很高兴能用go语言解出这道题,学以致用何尝不是一种成就!