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

51 阅读1分钟

当青训营遇上码上掘金

主题介绍

现有 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 个单位的青豆。

这个题目与leetcode中的接雨水几乎一样[ ](42. 接雨水 - 力扣(LeetCode))

主要有三种解法: 1.双指针 2.单调栈 3.动态规划

双指针

个人认为双指针是做好理解也做容易想到的做法。

QQ图片20230128085559.png

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

func max(a, b int) int {
    if a > b {
        return a
    }
    return b
}

单调栈

QQ图片20230128085559.png

func trap(height []int) (ans int) {
    stack := []int{}
    for i, h := range height {
        for len(stack) > 0 && h > height[stack[len(stack)-1]] {
            top := stack[len(stack)-1]
            stack = stack[:len(stack)-1]
            if len(stack) == 0 {
                break
            }
            left := stack[len(stack)-1]
            curWidth := i - left - 1
            curHeight := min(height[left], h) - height[top]
            ans += curWidth * curHeight
        }
        stack = append(stack, i)
    }
    return
}

func min(a, b int) int {
    if a < b {
        return a
    }
    return b
}

动态规划

QQ图片20230128085559.png

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

    leftMax := make([]int, n)
    leftMax[0] = height[0]
    for i := 1; i < n; i++ {
        leftMax[i] = max(leftMax[i-1], height[i])
    }

    rightMax := make([]int, n)
    rightMax[n-1] = height[n-1]
    for i := n - 2; i >= 0; i-- {
        rightMax[i] = max(rightMax[i+1], height[i])
    }

    for i, h := range height {
        ans += min(leftMax[i], rightMax[i]) - h
    }
    return
}

func min(a, b int) int {
    if a < b {
        return a
    }
    return b
}

func max(a, b int) int {
    if a > b {
        return a
    }
    return b
}