码上掘金之撒青豆 | 青训营笔记

41 阅读2分钟

当青训营遇上码上掘金

本堂课重点内容

  • 撒青豆

题目描述

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

image.png

题目分析

如图所示
第一列无法存放青豆
第二列可以存放4 - 0 = 4个青豆
第三列可以存放4 - 2 = 2个青豆
...

可以知道当前列可以存放的青豆数与隔壁左右柱子高度有关

题目解法

  1. 最直观的思路就是暴力解决
    思路是对于每一列,找左边和右边最高的柱子,然后如果左右最高柱子高度的较小值比本列高度要大,那么可以存放相应的青豆,否则无法存放
func gatherGreenBeans(height []int)int {
    size := len(height)
    sum := 0
    for i := 1; i < size - 1; i++ {
        leftMax, rightMax := 0, 0
        // 找右边最高的柱子
        for j := i; j < size; j++){
            rightMax = max(rightMax, height[j])
        }
        // 找左边最高的柱子
        for j := i; j >= 0; j--{
            leftMax = max(leftMax, height[j]);
        }
        // 如果自己就是最高的话,
        // leftMmax == rightMax == height[i]
        sum += min(leftMax, rightMax) - height[i];
    }
    return sum;
}

缺陷:时间复杂度O(N2)O(N^2)
优化思路:先计算备忘录用于保存当前列左边和右边最高柱子的高度,使时间复杂度降到O(N),但是空间复杂度提升到了O(N)

  1. 双指针算法
    思路:左右最高柱子的高度值可以“边走边算”,leftMax保存height[0,...,left]最高柱子的高度值,rightMax保存height[right,...,size]最高柱子的高度值,当leftMax<rightMax时,可以计算位于left的列可以存放的青豆数,由于每一列可以存放的青豆数取决于左右最高柱子的较小值,因此不需要关心更大的那一边。

拓展

其实这就是42. 接雨水 - 力扣(LeetCode)题目的变种