【困难】42. 接雨水

题目

42. 接雨水

  1. 接雨水

给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。

示例 1:

输入:height = 0,1,0,2,1,0,1,3,2,1,2,1

输出:6

解释:上面是由数组 0,1,0,2,1,0,1,3,2,1,2,1 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。

示例 2:

输入:height = 4,2,0,3,2,5

输出:9

提示:

n == height.length

1 <= n <= 2 * 104

0 <= heighti <= 105

解题

初步想法:以每一个水平面(连通盛水区)为计算单元。只需要找到这个盛水区的两端就行。依次遍历左板,顺着从左向右找不小于左板的作为右板。

问题:4,2,3 这种到最后左高右低的情况不能覆盖

打补丁:最后时候留一个flag(找到左板找不到不小于左板的右板),从右向左再重复遍历

改进:直接找到最高板,左右分别计算。

go 复制代码
func trap(height []int) int {
    
    for{
        if len(height)>0 && height[0] == 0{ 
            height = height[1:]
        } else {
            break
        }
    }
    
    if len(height)<3{
        return 0
    }
    
    re := 0
    imax, max := 0, 0
    
    for ix, v := range height{
        if max < v{
            max = v
            imax = ix
        }
    }
 
    for i:=0; i<=imax; {
        left := i
        i++

        for left<imax-1 && height[i]<height[left]{
            i++
            if i > imax{
                left++
                i = left+1
            }
        }
        if i == left+1{
            continue
        }
        re += count(left, i, height)
    }

    
    for i:=len(height)-1; i>=imax; {
        right := i
        i--

        for right>imax+1 && height[i]<height[right]{
            i--
            if i < imax{
                right--
                i = right - 1
            }
        }
        if i == right-1{
            continue
        }
        re += count(i, right, height)
    }

    return re

}

func count(left, right int, height []int) int{
    area := min(height[left], height[right]) * (right-left-1)
    for i:= left+1;i<right;i++{
        area-=height[i]
    }
    return area
}

问题: 初步没加判断 len(height)>0 ...... 小错不断,,,好低级


看了题解自己写一遍动态规划法:

go 复制代码
func trap(height []int) int {
 
    left := make([]int, len(height))
    right := make([]int, len(height))
    
    left[0] = 0
    right[len(height)-1] = 0

    for i:=1; i<len(height);i++{
        if height[i-1] > left[i-1]{
            left[i] = height[i-1]
        }else{
            left[i] = left[i-1]
        }
    }
    for i:=len(height)-2; i>=0;i--{
        if height[i+1] > right[i+1]{
            right[i] = height[i+1]
        }else{
            right[i] = right[i+1]
        }
    }

    re := 0
    for i:=0 ; i<len(height);i++{
        re += max(min(left[i], right[i])-height[i], 0)
    }
    return re

}

问题:

  1. 最后没考虑max的情况,有些例子里当height[i]min(left[i], right[i])大的时候出现负数......
  2. height[i-1] > left[i-1]height[i-1]与后面的比较

题解

方法一:动态规划

1

go 复制代码
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
}
作者:力扣官方题解
链接:https://leetcode.cn/problems/trapping-rain-water/solutions/692342/jie-yu-shui-by-leetcode-solution-tuvc/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

时间:O(n)

空间:O(n)

方法二:单调栈

2

go 复制代码
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
}
作者:力扣官方题解
链接:https://leetcode.cn/problems/trapping-rain-water/solutions/692342/jie-yu-shui-by-leetcode-solution-tuvc/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

时间:O(n)

空间:O(n)

方法三:双指针

go 复制代码
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
}
作者:力扣官方题解
链接:https://leetcode.cn/problems/trapping-rain-water/solutions/692342/jie-yu-shui-by-leetcode-solution-tuvc/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

时间:O(n)

空间:O(1)

长进

  1. 问题: 初步没加判断 len(height)>0 ...... 小错不断,,,好低级
  2. 出现问题的用例
    • 4,2,3

    • 0

    • 0,1,2,0,3,0,1,2,0,0,4,2,1,2,5,0,1,2,0,2 这个是使用flag方法,和用最大值基本一致,但是写的有bug,没再改,直接改为最大值方案。
  3. 后续自己复盘重写一下单调栈和双指针
相关推荐
张忠琳9 小时前
【Go 1.26.4】(Part 1) Go 1.26.4 超深度源码分析 — 总体架构与模块全景
开发语言·golang
小欣加油10 小时前
leetcode1926 迷宫中离入口最近的出口
数据结构·c++·算法·leetcode·职场和发展
烬羽13 小时前
从零理解树与二叉树:用 JS 带你手撕遍历和递归
javascript·数据结构
YHL13 小时前
🚀从零理解树与二叉树 —— 概念、实现与遍历
前端·javascript·数据结构
协享科技13 小时前
Spring Boot 与 Go 双服务架构实践:从单体拆分到通信设计
java·人工智能·spring boot·后端·架构·golang·ai编程
JieE21214 小时前
JS 到底有多少种数据类型?从ECMA规范到内存本质,一文彻底搞懂
javascript·数据结构·面试
努力努力再努力wz14 小时前
【内存管理与高并发内存池系列】从 mmap 到 malloc:文件映射、匿名映射与 glibc 内存分配机制详解
linux·c语言·数据结构·数据库·c++·qt·链表
八解毒剂14 小时前
数据结构-平衡二叉树——对二叉搜索树的优化
数据结构·c++·算法
Darling噜啦啦16 小时前
JavaScript 数组深度解析:从纯函数到二维数组陷阱,一文吃透前端数据结构核心
前端·javascript·数据结构
周杰伦的稻香16 小时前
Go + Redis:本地部署高性能图片主色调提取服务
开发语言·redis·golang