「青训营 X 码上掘金」(四)攒青豆·题解及分析

33 阅读2分钟

当青训营遇上码上掘金,本文为题解及思路分析。

1 原题呈现

主题 4:攒青豆

现有 n 个宽度为 1 的柱子,给出 n 个非负整数依次表示柱子的高度,排列后如下图所示,此时均匀从上空向下撒青豆,计算按此排列的柱子能接住多少青豆。(不考虑边角堆积)

image.png

以下为上图例子的解析:

输入: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
}