【LeetCode】42. 接雨水_LawsonAbs的博客-程序员秘密

技术标签: # LeetCode  算法  leetcode  OJ题解  

0.总结

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

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       

下面这版代码ac不了,仅当作一个无效版本看看而已~

'''
思想
使用单调栈。具体来说:
(1)顺序遍历所有的数组,入栈规则如下:
a.如果当前比栈顶大,那么入栈(入栈的是数组下标);
b.如果当前比栈顶小,那么计算当前这个黑块占得面积,后面计算的时候需要扣除掉
(2)轮流访问整个数组,直到结束。返回结果
'''
class Solution:
    def trap(self, height: List[int]) -> int:
        rain_num = 0 
        stack = [0] # stack 中存储的是下标。先放入第一个元素
        block = 0 # 遮挡住的面积
        for i in range(1,len(height)):
            # 如果不低于栈顶元素,那么这个时候就要考虑计算雨水点数了
            if height[i] >= height[stack[-1]]:                
                # 找到第一个高度不低于当前高度的位置
                while(height[i] > height[stack[-1]]): # 依次出栈
                    stack.pop() # 出栈
                
                length = i - stack[-1] - 1  # 计算长方形的长
                width = min(height[i],height[stack[-1]])
                cur_area = length * width - block # 
                rain_num += cur_area
                
                # 这里不是重置为0
                block +=  (i-stack[-1]) * height[i]
                stack.pop() # 移除栈顶
                stack.append(i)
                                
            else: # 较小值也要入栈
                stack.append(i)
                block += height[i]
        return rain_num
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/liu16659/article/details/125175332

智能推荐

DataTables 的 实例 《一》_MaxCode-1的博客-程序员秘密

1.加载需要的js/css文件2.function del(id){ alert(id);}var table;$(document).ready(function() { table = $('#example').dataTable( { "processing": true, "aoColumns" : [

ESXI 6.7全面系统教程~汇总_esxi使用教程_我顾子晨的博客-程序员秘密

许可证:0A65P-00HD0-375M1-M097M-22P7Hesxi 是一个脱机系统,也是一个虚拟机系统与vmware 相比,它可以直接运行在硬件上,这样可以减少资源浪费,一般用于服务器上;

走进VR开发世界(4)——走进VR游戏开发的世界_shuimanting520的博客-程序员秘密

注: 原文2016年2月发表于公司内部社区, 最近才由同事转载出来, 删去了文中引用的一些内部文章和视频. 在这里我也只是把外网版本转过来, 留做备份.背景介绍我们组在2014年下半年尝试开发了一款 XboxOne 平台的体感游戏, 2015年上半年进行收尾工作的同时, 结合之前积累的体感交互经验, 开始进行 VR 游戏的预研工作. 在这近一年的时间里, 一方面从外

PHP设计模式之AbstractFactory模式_hcb0825的博客-程序员秘密

<br />通常工厂模式用来创建某类固定模式的对象,但是某些项目中我们经常要创建不同类型的对象,比如在游戏中,通常有很多角色,这时就会用的抽象工厂方法,AbstractFactory模式典型的结构图为:<br /> <br />注释:UML连线中虚线箭头表示依赖关系,其它的不用说了吧!<br /> <br />下面是一位大牛的代码,来源于:http://www.phppan.com/?s=%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F<br /><?php/** * 抽象工

使用SpEL表达式来获取SpringData Jpa在更新数据时传递的对象参数的属性_spel表达式获取对象属性__云卷云舒_的博客-程序员秘密

一、问题描述 使用Jpa时我们经常需要对数据库中的数据进行更新操作,通常更新数据库的数据有两种方法。 第一种是通过Jpa的实体管理器对托管态实体对象进行更新,对托管态实体对象的更新即意味着对数据库对应记录的更新。这种方法虽然使用起来比较简单,但也存在全字段更新、意料之外的记录更新、业务层跟持久层职责不清等问题。示例如下:@[email protected]...

Python实现遗传算法_哇哇咔咔MZ:y的博客-程序员秘密

遗传算法属于一种优化算法。如果你有一个待优化函数,可以考虑次算法。假设你有一个变量x,通过某个函数可以求出对应的y,那么你通过预设的x可求出y_pred,y_pred差距与你需要的y当然越接近越好,这就需要引入适应度(fitness)的概念。假设fitness = 1/(1+ads(y_pred - y)),那么误差越小,适应度越大,即该个体越易于存活。设计该算法的思路如下:(1)初始化种群,即在我需要的区间如[-100,100]内random一堆初始个体[x1,x2,x3...],这些个体

随便推点

ant.vue富文本编辑器_适用于Vue.js的简单轻巧的Trix RTF富文本编辑器组件_cuk5340的博客-程序员秘密

ant.vue富文本编辑器 Vue-Trix文字编辑器 (Vue-Trix Text Editor)Simple and lightweight Trix rich-text editor component for Vue.js. Vue.js的简单轻量级Trix RTF编辑器组件。 安装 (Installation)NPM NPM $npm install --save vue-...

手把手学习Vue3.0:Vue3.0正确使用Bus总线mitt实现组件间通信和传参_mittbus_帅哥趣谈的博客-程序员秘密

背景在使用Vue做后台管理系统的过程中,需要实现组件间的参数传递。Bus方式非常简洁方便,却遇到一个奇怪的现象,我单击菜单区域,需要在header中展示操作导航,内容区域做展示。结果header区域没有反应。下面我分别介绍Vue3.0如何集成Bus,同时复盘一下问题的整个过程。Vue3.0集成BusVue到3.0之后的Bus的方式变成了使用mitt。2.0是通过创建一个空的Vue来作为总线。 使用emit来注册,emitt("type","event");,可以先这样理解:第一个参数可.

SpringBoot与缓存使用及原理_何星平的博客-程序员秘密

原创 SpringBoot与缓存使用及原理(上) ...

【笔记】Mybatis高级查询(四)--使用resultMap的<collection>标签实现一对多和多对多查询_resultmap 一对多 total_Moss Huang的博客-程序员秘密

&amp;amp;amp;amp;amp;lt;collection&amp;amp;amp;amp;amp;gt;集合的嵌套结果映射就是指通过一次SQL查询将所有的结果查询出来,然后映射到不同的对象中。在一对多的关系中,主表一条数据会对应关联表的多条数据。因此一般查询时会查询出多条结果,按照一对多的数据映射时,最终的结果数会小于等于查询的总记录数。在RBAC权限系统中一个用户拥有多个角色,一个角色又拥有多个权限。以下例子通过嵌套查询查出某个用户及用户角色。1. ...

推荐文章

热门文章

相关标签