当青训营遇上码上掘金

54 阅读2分钟
  • 主题 4:攒青豆

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

image.png

这个问题其实是一道非常经典的Leetcode题目——42. 接雨水 - 力扣(LeetCode)

这道题的最佳解法是使用双指针,如下图所示,在橙色区域内所能装下的最大青豆数量是由两端的柱子中更矮的一段所决定的,同时两端的柱子都等于或者高于中间的柱子。因此,使用双指针从两端向中间进行遍历,记录当前指针所在的位置两端的柱子高度,就可以计算出当前位置可以攒的青豆数量n[i]=min(height[h_l],height[h_r])-height[i],当两个指针重合时结束。

image.png

h_l,h_r的更新规则为:

  • 首先移动高度更低的柱子对应的指针,保证得到最优解。
  • 如果指针移动过程中遇到了比最低的柱子更高的柱子,则将最低的柱子高度更新为当前柱子的高度。

代码如下:

func trap(height []int) int {
    l := 0
    r := len(height) - 1
    h_l := 0
    h_r := 0
    ans := 0

    for l < r {
        if (height[l] > h_l) {
                h_l = height[l]
        }
        if (height[r] > h_r) {
             h_r = height[r]
        }
        if (height[l] < height[r]) {
            ans = ans + h_l - height[l]
            l = l + 1
        } else {
            ans = ans + h_r- height[r]
            r = r - 1
        }
    }
    return ans
}

对于这个问题,还有一个进阶版本,将一维的水池展开成二维的。每个位置能接住雨水的高度需要判断上下左右四个相邻柱子的高度,这道题的最优解法是最短路,题解如下。从一维变化到二维,问题本质的变化还是很大的。

【宫水三叶】经典 Dijkstra 运用题 - 接雨水 II - 力扣(LeetCode)