当青训营遇上码上掘金,本文为题解及思路分析。
1 原题呈现
主题 4:攒青豆
现有 n 个宽度为 1 的柱子,给出 n 个非负整数依次表示柱子的高度,排列后如下图所示,此时均匀从上空向下撒青豆,计算按此排列的柱子能接住多少青豆。(不考虑边角堆积)
以下为上图例子的解析:
输入:height = [5,0,2,1,4,0,1,0,3]
输出:17
解析:上面是由数组 [5,0,2,1,4,0,1,0,3] 表示的柱子高度,在这种情况下,可以接 17 个单位的青豆。
2 思路分析
我们知道一个装水桶能装多少水取决于水桶得最短板。攒青豆也是类似,高度数组的长短也局限着攒青豆的数量。那如何通过高度数组计算出能攒多少个单位青豆呢?
最容易想到的办法就是使用模拟的方式遍历数组,即用双指针(left,right)来充当桶的两边, 桶的宽度=right-left-1, 两个指针能攒的青豆=宽度* min(height[left],height[right])。
当r指针遍历完数组就可以计算出结果。
即这道题的解法是使用双指针法。
首先,定义两个指针,一个指向数组的开头,一个指向数组的末尾。 然后,比较两个指针指向的数字,将较小的数字作为容器的高度,计算出容器能接住的水量(青豆量)。 最后,将较小的数字指针向中间移动,重复上述步骤,直到两个指针重合。
3 代码题解
//码上掘金:攒青豆·题解
//go:build ignore
// +build ignore
package main
import "fmt"
// 定义一个函数,用于计算柱子能接住多少青豆
func countPeas(height []int) int {
// 定义两个指针,一个指向数组的开头,一个指向数组的末尾
left, right := 0, len(height)-1
ans := 0
// 比较两个指针指向的数字,将较小的数字作为容器的高度,计算出容器能接住的水量
for left < right {// 将较小的数字指针向中间移动,重复上述步骤,直到两个指针重合
minHeight := min(height[left], height[right])
if minHeight == height[left] {
left++
for left < right && height[left] < minHeight {
ans += minHeight - height[left]
left++
}
} else {
right--
for left < right && height[right] < minHeight {
ans += minHeight - height[right]
right--
}
}
}
return ans
}
func min(x, y int) int {
if x < y {
return x
}
return y
}
func main() {
// 调用函数计算柱子能接住多少青豆
height := []int{5, 0, 2, 1, 4, 0, 1, 0, 3}
fmt.Println(countPeas(height)) // 输出17
}