即使青豆攒几颗也要攒青豆 | 「青训营 X 码上掘金」主题创作

54 阅读2分钟

当青训营遇上码上掘金。

攒青豆

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

思路

这个题目可以使用双指针的方法解决,用指针leftright分别指向数组开头和结尾,同时,用变量leftMaxrightMax分别表示从左侧到left的最大高度和从右侧到right的最大高度,两个变量的初始值分别为0n-1

定义变量ans表示能接住多少青豆。在每个位置能接住的青豆数量等于该位置左侧和右侧最大高度的较小值减去该位置的高度。可以用公式以下公式表示

ans += min(leftMax, rightMax) - height[i]

在go代码里面可以写成

for left <= right {
	if leftMax < rightMax {
		ans += leftMax - height[left]
	} else {
		ans += rightMax - height[right]
	}
}

在计算完当前位置能够接住的青豆之后,我们需要根据左右两侧的最大高度来更新leftMaxrightMax。当leftMax < rightMax意味着left的高度不会对接住青豆的数量造成影响,因为left已经被左侧的最大高度leftMax所限制,因此将left向右移动一位,并将leftMax更新为当前位置的高度。类似的,当leftMax >= rightMax时,将right向右移动一位,并将rightMax更新为当前位置的高度。如此迭代下去,直到两个指针相遇。

在代码里补充上

for left <= right {
	if leftMax < rightMax {
		ans += leftMax - height[left]
		left++
		if left < n && height[left] > leftMax {
			leftMax = height[left]
		}
	} else {
		ans += rightMax - height[right]
		right--
		if right >= 0 && height[right] > rightMax {
			rightMax = height[right]
		}
	}
}

使用bufio.NewReader从标准输入中读取用户输入的数组。使用strings.Index函数来确定前面和后面,使用strings.Split函数将输入字符串拆分为子字符串,然后使用strings.TrimSpacestrconv.Atoi函数将尾随空格去除和每个子字符串转换为整数。将代码完善,就成下面的样子

package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

func trap(height []int) int {
	n := len(height)
	if n == 0 {
		return 0
	}

	left, right := 0, n-1
	leftMax, rightMax := height[0], height[n-1]
	ans := 0

	for left <= right {
		if leftMax < rightMax {
			ans += leftMax - height[left]
			left++
			if left < n && height[left] > leftMax {
				leftMax = height[left]
			}
		} else {
			ans += rightMax - height[right]
			right--
			if right >= 0 && height[right] > rightMax {
				rightMax = height[right]
			}
		}
	}

	return ans
}

func main() {
	fmt.Println("请输入高度与柱子数,数组个数为柱子数,数组内的数为高度,示例:[5,0,2,1,4,0,1,0,3],意思为有9个柱子,高度分别是5,0,2,1,4,0,1,0,3")
	input := bufio.NewReader(os.Stdin)
	n, _ := input.ReadString('\n')

	var height []int
	start := strings.Index(n, "[") + 1
	end := strings.Index(n, "]")
	parts := strings.Split(n[start:end], ",")
	for _, part := range parts {
		value, err := strconv.Atoi(strings.TrimSpace(part))
		if err != nil {
			panic(err)
		}
		height = append(height, value)
	}

	fmt.Println(trap(height))
}

Arknights主题和Arknights有什么关系吗