【LeetCode】42. 接雨水

本文详细解析了LeetCode上经典问题“接雨水”的解决思路与实现方法。利用单调栈原理,文章阐述了如何有效避免重复计算,实现精准求解。通过具体示例说明了算法的运作流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

0.总结

  • 为了防止重复计算,求高度的时候 -height[top]是点睛之笔。而我的想法则是仅限于累积求出每次需要扣除的面积,但是放在这里使用的话,不好更新。
  • 单调栈的性质便是:栈中的元素从某个角度来看是单调的。

1.题目

在这里插入图片描述

2.思想

这道题还是挺精妙的,我知道用单调栈做,但是实现起来还是不容易。关键问题是,接到的雨水的性状是不规则的,怎么保证得到的雨水没有重复计算就是一个关键点。本题利用自身的一个矩形形状来扣除掉不需要计算的规则。具体如下:

  • 栈中存放的数据规则:栈底到栈顶是从大到小。
  • 每次计算雨水点数时,都存储了三个元素【确实只有至少长度为3的格子才有可能接到雨水】,分别是 height[left], height[top],height[cur] 其满足的条件是:
    height[left] >= height[top]
    height[top] < height[cur]
    这个 top 就是需要扣除的多余面积。如下图:
    在这里插入图片描述

因为这里的top是0,所以面积就是1。
在这里插入图片描述

这里因为top 是1,所以 min(cur,left) - top = 1 相当于只求了红框中面积,这样就避免了重复计算。

3.代码

class Solution:
    def trap(self, height: List[int]) -> int:
        height.append(0)
        res = 0
        stack = []
        stack.append(0) # 将0 位置的高度入栈
        for i in range(1,len(height)):
            # print(i,stack)
            # (1)如果当前位置的高度 小于 栈顶位置时,入栈。切记这里没有=
            if height[i] < height[stack[-1]]:
                stack.append(i)
            
            # 当前位置的高度大于等于栈顶位置,那么可以接雨水了。【等于的这个情况是为了消耗掉】
            else:
                if len(stack) <2 : # 如果当前栈中元素还不够,则继续入栈
                    stack.append(i) # 将当前这个节点放到栈中
                    continue
                else: # 已经超过2个元素了
                    while(len(stack)>=2
                        and height[i] >= height[stack[-1]] # 注意这个等于号,还是相当关键的
                        and height[stack[-2]] > height[stack[-1]]
                        ):
                        top = height[stack[-1]]
                        left = height[stack[-2]]
                        width = i - stack[-2] - 1 # 求出宽
                        cur_height = min(height[i],left) - top  # 求出高
                        cur_area = width * cur_height

                        res += cur_area
                        stack.pop() # 删除最后一个元素
                    stack.append(i) # 将当前这个节点放到栈中。这个也是比较重要的点
        return res       

(20240825)重写了这道接雨水的题。这道题不是那么好写,关键点全在while循环中,需要用心体会。

class Solution:
    def trap(self, height: List[int]) -> int:
        if len(height) < 3:
            return 0
        # 存储的是每个下标
        stack = []
        stack.append(0)
        res = 0
        for i in range(1, len(height)):
            cur = height[i]
            if cur < height[stack[-1]]: # 如果当前的高度小于栈中最后一个高度
                stack.append(i)
            else:
                # 本题需要注意的地方是:
                # 1. while循环必须要同时满足如下几个条件,才能计算面积
                # 2. 当 cur >= height[stack[-1]] 的时候,也就保证即使相同高度,也能计算(这是为了简化)
                # 3. 注意cur_width 是通过当前位置 i 与 left 围成的面积,所以要与left的位置计算宽度
                while( len(stack) >= 2 and height[stack[-2]] > height[stack[-1]] 
                        and cur >= height[stack[-1]]):
                    left = height[stack[-2]]
                    top = height[stack[-1]]
                    cur_height = min(cur,left) - top
                    cur_width = i - stack[-2] - 1
                    cur_res = (cur_height * cur_width) 
                    # print(cur_height, cur_width, cur_res, i, cur)
                    res += cur_res
                    del stack[-1]
                    # print(stack)

                stack.append(i)
                # print(stack)
        return res
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

说文科技

看书人不妨赏个酒钱?

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值