攒青豆 | 青训营 X 码上掘金

73 阅读3分钟

当青训营遇上码上掘金

主题介绍(题目介绍)

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

以下为上图例子的解析:
​
输入:height = [5,0,2,1,4,0,1,0,3]  
输出:17  
解析:上面是由数组 [5,0,2,1,4,0,1,0,3] 表示的柱子高度,在这种情况下,可以接 17 个单位的青豆。

image.png

分析:

这个题目好像力扣的某一个题目,具体的名字我忘记了。好像是接雨水?

上面掘金给出的图片解析非常的形象生动,这个青豆是哪个运营想出来的?

可以看出这个题目是有关于木桶效应。木桶能装多少水取决于最短的板子而不是最长的板子。所以应该先算出两侧最短的长度

任意一个位置,只要你知道该位置的左边界和右边界就知道这个位置能装多少豆了。

模拟思路

如题目所示:(从左到右遍历)

[5,0,2,1,4,0,1,0,3]

第一步:5是柱子,不统计

第二步:0表示没有,右边最大的值为4,4-0=4

第三步:2,右边最大的值为4 小于左边最大的值5 4-2=2

第四步:1,左右边最大值的较小值为4 4-1=3

第五步:4 左右最大值的最小值为4 (即是自己)4-4=0

第六步:0 左右边最大值的较小值为3 3-0=3

第七步:1 左右边最大值的较小值为3 3-1=2

第八步: 0 左右边最大值的较小值为3 3-0=3

第九步:3 柱子,不统计

最后将其总数相加 4+2+3+0+3+2+3 = 17

以此类推,遍历整个数组就可以得出整个数组能接到多少青豆了。

代码思路

首先创建相关的变量

遍历不包含首尾的数组,创建一个计算左右最大值的函数,在遍历的同时每次都调用这个函数。并保存这两个的值(go的多参数返回真好用),最后比较两个值的大小,用当前遍历的值减去两者的小值,最后再将其加上总数即可。

注意的地方:

  • 两侧的数值不计入统计
  • 注意函数中的i和数组的index越界问题

如果代码或者思路有错误,请指出。感激!

总代码:

package main
​
import "fmt"func main() {
    // 定义总豆子
    var total int = 0
    // 定义示例数组
    var beans = []int{5, 0, 2, 1, 4, 0, 1, 0, 3}
    // 传入函数
    total = calcTotal(beans)
    fmt.Println(total)
}
func calcTotal(beans []int) int {
    total := 0
    //left := 0
    right := len(beans)
    // 只有两个或者一个的情况下
    if right == 1 || right == 2 {
        return 0
    }
    //leftMax := 0
    //rightMax := 0
    for i, value := range beans {
        leftMax, rightMax := calcMax(beans, i)
        // 最左侧和最右侧 为柱子,不可取
        if i == 0 || i == right-1 {
            continue
        }
        // 左小右大
        if leftMax < rightMax  {
            total+=leftMax-value
        }else {
            total+=rightMax-value
        }
        fmt.Printf("第%d个元素 左最大值:%d 右最大值:%d 总豆子数:%d \n",i,leftMax,rightMax,total)
    }
    return total
}
​
// 计算左侧和右侧的最大值
func calcMax(beans []int, i int) (int, int) {
    //temp := i
    left := i
    right := i
    leftMax := 0
    rightMax := 0
    // 两次遍历
    for left >= 0 {
​
        //leftMax=leftMax>beans[left]? 什么残废语言不支持三元运算符 
        if leftMax < beans[left] {
            leftMax = beans[left]
        }
        left -= 1
    }
    for right < len(beans) {
​
        //leftMax=leftMax>beans[left]?
        if rightMax < beans[right] {
            rightMax = beans[right]
        }
        right += 1
    }
    return leftMax, rightMax
}
​

运行结果

  • 第1个元素 左最大值:5 右最大值:4 总豆子数:4
  • 第2个元素 左最大值:5 右最大值:4 总豆子数:6
  • 第3个元素 左最大值:5 右最大值:4 总豆子数:9
  • 第4个元素 左最大值:5 右最大值:4 总豆子数:9
  • 第5个元素 左最大值:5 右最大值:3 总豆子数:12
  • 第6个元素 左最大值:5 右最大值:3 总豆子数:14
  • 第7个元素 左最大值:5 右最大值:3 总豆子数:17
  • 17