「青训营 X 码上掘金」主题 4:攒青豆

77 阅读2分钟

当青训营遇上码上掘金

这篇文章是对于青训营的【「青训营 X 码上掘金」主题创作活动入营版 开启! - 掘金 (juejin.cn)】的主题4的一个个人解决方案。

题目如下:

  • 主题 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 个单位的青豆。

在阅读完这道题目之后,我的脑中浮现了一个思路,用双指针法。从左往右和从右往左分别遍历每个柱子,如果当前的柱子高度比较小,则向右移动左指针,并在当前位置计算青豆的数量;如果当前的柱子高度比较大,则向左移动右指针,并在当前位置计算青豆的数量。最后可以得到总的青豆数量。

之后尝试使用go语言对该题进行解题,我的代码如下

package main

import "fmt"

func trap(height []int) int {
   left, right := 0, len(height)-1
   leftMax, rightMax := 0, 0
   result := 0
   for left < right {
      if height[left] < height[right] {
         if height[left] >= leftMax {
            leftMax = height[left]
         } else {
            result += leftMax - height[left]
         }
         left++
      } else {
         if height[right] >= rightMax {
            rightMax = height[right]
         } else {
            result += rightMax - height[right]
         }
         right--
      }
   }
   return result
}

func main() {
   height := []int{5, 0, 2, 1, 4, 0, 1, 0, 3}
   result := trap(height)
   fmt.Println(result)
}

代码思路如下:

首先,在函数trap()内,确定了柱子的数量。如果没有柱子,则返回0。

然后,创建了两个数组leftMax和rightMax,分别用于存储每个柱子左侧和右侧的最高柱子的高度。

使用循环预处理leftMax数组。leftMax[0]设置为柱子高度的第一个元素,并依次处理leftMax[1]到leftMax[n-1]。

同样的,使用循环预处理rightMax数组。rightMax[n-1]设置为柱子高度的最后一个元素,并从右到左处理rightMax[n-2]到rightMax[0]。

最后,通过计算,查找左侧和右侧最高柱子中较低的那个,减去当前柱子的高度,累加到结果中。

最后返回总共能接住的青豆数。

输入样例之后得到预期结果17,如果大家对于这道题有更好的思路,或者可以对我的算法进行优化,欢迎留言讨论。

最后附上本人代码