【Python刷力扣hot100】42. Trapping Rain Water

问题

给定 n 个非负整数表示海拔高度,其中每个条形的宽度为 1 ,计算下雨后可以接多少水。

例1:

Input: height = [0,1,0,2,1,0,1,3,2,1,2,1]

Output: 6

Explanation: 上述海拔图(黑色部分)由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示。在这种情况下,共可储存 6 个单位的雨水(蓝色部分)。

例2:

Input: height = [4,2,0,3,2,5]

Output: 9

约束:

  • n == height.length
  • 1 <= n <= 2 * 104
  • 0 <= height[i] <= 105

解1:暴力

我们只需计算每个"黑色条形"上方可以累积多少"雨水",之后求和,就得到了最终的雨水数量。

  • 对最左和最右的"黑色条形",显然不会累积雨水
  • 对中间的"黑色条形",记其海拔为m,当其两侧均存在比它高的海拔,才有可能累积雨水
    • 找到其左侧比它高的最高海拔记为l,右侧比它高的最高海拔记为r,则m上方累积的雨水数量为 m i n ( l , r ) − m min(l,r)-m min(l,r)−m

时间复杂度 O ( n 2 ) O(n^2) O(n2):对中间的每个海拔,都要遍历一次两侧的海拔,时间复杂度为 O ( ( n − 2 ) ∗ ( n − 1 ) ) = O ( n 2 ) O((n-2)*(n-1))=O(n^2) O((n−2)∗(n−1))=O(n2)

空间复杂度 O ( 1 ) O(1) O(1):随着问题规模n的增大, 需要的额外空间不变

python 复制代码
class Solution:
    def trap(self, height: List[int]) -> int:
        n = len(height)
        ans = 0
        for i in range(n):
            lh = 0  # left height
            rh = 0  # right height
            for l in range(0, i):
                lh = max(lh, height[l])
            for r in range(i + 1, n):
                rh = max(rh, height[r])
            if lh > height[i] and rh > height[i]:
                ans += min(lh, rh) - height[i]
        
        return ans

超时了,但能过319个用例,说明思路没问题

解2:动态规划,左右遍历,空间换时间

还是接着刚才的思路,通过遍历解决问题,但是这次采用两次遍历,一次正向,一次反向,从而得到需要的最大海拔。

  • 正向遍历:用数组lh记录对应下标左侧的最大海拔。如lh[2]记录了height[0]height[1]height[2]中的最大值。
  • 反向遍历:用数组rh记录对应下标右边侧的最大海拔。如lh[2]记录了height[2]height[3]height[4]中的最大值(总长度为5)。
  • 之后用lhrh计算每个海拔头上的雨水,求和

时间复杂度 O ( n ) O(n) O(n):需要遍历2次数组,还要遍历一次lhrh,时间复杂度为 O ( 4 n ) = O ( n ) O(4n)=O(n) O(4n)=O(n)

空间复杂度 O ( n ) O(n) O(n):需要用数组lhrh存储中间结果

python 复制代码
class Solution:
    def trap(self, height: List[int]) -> int:
        n = len(height)
        ans = 0
        lh = [0] * n  # left height
        rh = [0] * n  # right height

        now_max=0
        for i in range(n):
            now_max=max(now_max,height[i])
            lh[i]=now_max
        now_max=0
        for i in range(n-1,-1,-1):
            now_max=max(now_max,height[i])
            rh[i]=now_max

        for i in range(1,n-1):
            if lh[i-1]>height[i] and rh[i+1]>height[i]:
                # print(f"rain{i}={min(lh[i-1],rh[i+1])-height[i]}")
                ans += min(lh[i-1],rh[i+1])-height[i]

        return ans

过了

解3:单调栈

解4:双指针

补充

接雨水可视化

python 复制代码
import matplotlib.pyplot as plt
import numpy as np

# 设置中文显示
plt.rcParams["font.family"] = ["SimHei"]
plt.rcParams["axes.unicode_minus"] = False  # 解决负号显示问题

def trap_rain_water_visualization(height):
    n = len(height)
    if n == 0:
        return
    
    # 计算左右最大高度数组
    left_max = [0] * n
    right_max = [0] * n
    left_max[0] = height[0]
    for i in range(1, n):
        left_max[i] = max(left_max[i-1], height[i])
    right_max[-1] = height[-1]
    for i in range(n-2, -1, -1):
        right_max[i] = max(right_max[i+1], height[i])
    
    # 计算每个位置的雨水量
    water = [max(0, min(left_max[i], right_max[i]) - height[i]) for i in range(n)]
    
    # 绘图
    x = np.arange(n)
    fig, ax = plt.subplots(figsize=(8, 6))
    
    # 绘制柱子(黑色表示原高度)
    ax.bar(x, height, width=1, color='black', edgecolor='black')
    
    # 绘制雨水(蓝色表示雨水)
    ax.bar(x, water, width=1, bottom=height, color='blue', alpha=0.7, edgecolor='blue')
    
    # 设置标题和标签
    ax.set_title('接雨水可视化')
    ax.set_xlabel('位置')
    ax.set_ylabel('高度')
    ax.set_xticks(x)
    ax.set_xticklabels(x)
    plt.grid(False)
    plt.show()

# 测试数组
height = [4, 2, 0, 3, 2, 5]
trap_rain_water_visualization(height)

参考

https://leetcode.cn/problems/trapping-rain-water

相关推荐
一只安3 小时前
从零开发AI(不依赖任何模型)
人工智能·python
Miraitowa_cheems3 小时前
LeetCode算法日记 - Day 88: 环绕字符串中唯一的子字符串
java·数据结构·算法·leetcode·深度优先·动态规划
2501_938782094 小时前
实战 Python NLP:处理 PDF 文档批量提取文本并进行主题建模
python·自然语言处理·pdf
成长痕迹4 小时前
【Python与Matlab数据分析对比】
python·matlab·数据分析
11年老程序猿在线搬砖4 小时前
如何搭建自己的量化交易平台
大数据·人工智能·python·自动交易·量化交易系统
消失的旧时光-19434 小时前
Kotlin 协程最佳实践:用 CoroutineScope + SupervisorJob 替代 Timer,实现优雅周期任务调度
android·开发语言·kotlin
错把套路当深情4 小时前
Kotlin保留小数位的三种方法
开发语言·python·kotlin
错把套路当深情4 小时前
Kotlin基础类型扩展函数使用指南
python·微信·kotlin
千里码aicood4 小时前
python+vue旅游购票管理系统设计(源码+文档+调试+基础修改+答疑)
vue.js·python·旅游