从零学算法42

news2024/10/6 12:24:56

42.接雨水
给定 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 <= height[i] <= 105

  • 我的原始人解法:遍历每个高度,然后从当前高度往后找,如果存在大于等于它的高度,就计算一次收集的雨水。比如 [4,1,2,5],那么收集的雨水量就是 (4-4) + (4-1) + (4-2),如果没有比它大的,由于雨水量只取决于低的高度,所以我们可以将其更新成他后面的第二高的高度,下一轮继续处理这一处,看能够和后面大于等于它的高度接多少雨水。
  •   public int trap(int[] height) {
          int n = height.length;
          int res = 0;
          for(int i = 0; i < n - 1; i++){
              int j = i + 1;
              int max = Integer.MIN_VALUE;
              while(j < n && height[j] < height[i]){
                  max = Math.max(max, height[j]);
                  j++;
              }
              // 后面存在大于等于它的高度
              if(j < n){
                  res += sum(height, i, j);
                  i = j - 1;
              }else{
                  height[i] = max;
                  i -= 1;
              }
          }
          return res;
      }
      // 计算 start ~ end 的雨水
      public int sum(int[] height, int start, int end){
          int sum = 0;
          for(int i = start; i < end; i++){
              sum += height[start] - height[i];
          }
          return sum;
      }
    
  • 前后缀分解:其实某一处的高度能否和前后组成接雨水的桶,取决于前后最大高度中的小的那个,所以求出对于每一个 height[i] 它的前面最大值 preMax[i] (0~i) 以及后面最大值 sufMax[i] (i~n-1) 就能知道这一处所能接的雨水量。比如 [1,2,0,3,5],对于 height[2] 的 0 来说,preMax[2] = 2, sufMax[2] = 5,那么它能储存的雨水就是 min(preMax[2],sufMax[2]) - height[2]
  •   public int trap(int[] height) {
          int n = height.length;
          int[] preMax = new int[n];
          preMax[0] = height[0];
          for(int i = 1; i < n; i++){
              preMax[i] = Math.max(preMax[i-1], height[i]);
          }
    
          int[] sufMax = new int[n];
          sufMax[n-1] = height[n-1];
          for(int i = n-2; i >= 0; i--){
              sufMax[i] = Math.max(sufMax[i+1], height[i]);
          }
    
          int res = 0;
          for(int i = 0; i < n; i++){
              res += Math.min(preMax[i], sufMax[i]) - height[i];
          }
          return res;
      }
    
  • 相向双指针: 根据上个解法可以优化,由于我们对于 preMax 以及 sufMax 数组的每个值都只需要在遍历到对应下标时用到一次,所以我们可以尝试用双指针和两个变量代替数组。遍历时不断更新 left 对应的 preMax 以及 right 对应的 sufMax,哪个 max 更小我们就将哪一边可以接的雨水计算一遍,对于这一边来说,和使用数组是等效的,而另一边如果实际上的 max 更大,那我们依旧是取这一边,所以没有影响。比如 [1,0,20,1],当我们遍历到高度为 0 处时,我们的 preMax=1, sufMax = 1,然后实际上 preMax=1, sufMax = 20,但这并不影响我们最终的计算结果,因为可接雨水只和更小的最大值有关,所以我们都取了小于等于 sufMax 的 preMax。即我们计算高度的那一边的 max 是实际上的 max,而另一边的 max 只可能大于等于这一边的 max,大于或等于都对结果无法造成影响。
  •   public int trap(int[] height) {
          int res = 0;
          int left = 0, right = height.length - 1;
          int preMax = 0, sufMax = 0;
          while(left < right){
              preMax = Math.max(preMax, height[left]);
              sufMax = Math.max(sufMax, height[right]);
              res += preMax <= sufMax? preMax - height[left++] : sufMax - height[right--];
          }
          return res;
      }
    
  • 单调栈:以上的解法为计算每一列的雨水相加,而单调栈则为计算每一行的雨水。令单调栈存储高度降低的趋势,比如 [2,1],当遇到上升趋势时(高度大于栈顶元素对应高度,此例为 1)就能计算该区间某一行的雨水,比如遇到了 3,那么 [2,1,3] 就组成一个高度降低又上升的图形,即形成了一个桶。
  • 雨水的面积我们采用长乘宽的形式计算,高我们需要取短边,即 2 和 3 中的 2,但还需要减去底边的高度,即高为 min(2,3) - 1,而宽则为 2,3 间相差的距离,为了计算宽度我们的栈就不能存储高度了,需要改为存储对应下标。这样比如 height = [2,1,3],我们的栈会存储 [0,1],遍历到 2 时高还是一样为 min(height[0],height[2]) - height[1],而宽直接就是 2 - 0 - 1
  • 单调栈算法的执行过程可以参考官方题解示意图
  •   public int trap(int[] height) {
          int res = 0;
          Stack<Integer> stack = new Stack<>();
          for(int right = 0; right < height.length; right++){
          	// 遇到上升趋势表示可能有桶了,因为如果前面没有下降趋势就还是没有桶,所以说可能
              while(!stack.isEmpty() && height[right] > height[stack.peek()]){
              	// 底边
                  int bottom = stack.pop();
                  // 如果前面没有高度了就没法组成桶了
                  if(stack.isEmpty())break;
                  // 左高度
                  int left = stack.peek();
                  // 宽为右高度下标 - 左高度下标 - 1
                  int currentWidth = right - left - 1;
                  // 高为小高度减底边高度
                  int currentHeight = Math.min(height[left], height[right]) - height[bottom];
                  res += currentWidth * currentHeight;
              }
              stack.push(right);
          }
          return res;
      }
    

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1659792.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

蚂蚁面试:DDD外部接口调用,应该放在哪一层?

尼恩说在前面&#xff1a; 在40岁老架构师 尼恩的读者交流群(50)中&#xff0c;最近有小伙伴拿到了一线互联网企业如字节、阿里、滴滴、极兔、有赞、希音、百度、网易、美团的面试资格&#xff0c;遇到很多很重要的面试题&#xff1a; DDD 的外部接口调用&#xff0c;应该放在…

Java方法和数组

方法 Java中的方法就是c语言中的函数。 方法的定义 定义格式如下 修饰符 返回值 方法名([参数列表]){代码块[return 返回值;] } //方括号[]括起来代表可以没有&#xff0c;不是必须有的方法名采用小驼峰命名&#xff08;就是有多个单词&#xff0c;第一个单词首字母小写其…

阅读送书抽奖?玩转抽奖游戏,js-tool-big-box工具库新上抽奖功能

先讨论一个问题&#xff0c;你做软件工作是为了什么&#xff1f;从高中选专业&#xff0c;就喜欢上了软件开发&#xff1f;还是当初毕业不知道干啥&#xff0c;不喜欢自己的专业&#xff0c;投入软件开发的怀抱&#xff1f;还是干着干着别的&#xff0c;突然觉得互联网行业真不…

前端技术交流群

欢迎来到前端筱园用户交流&#xff01;这是一个专注于前端编程技术、学习资源和行业动态的讨论平台。在这里&#xff0c;你可以分享经验、提问、回答问题&#xff0c;与其他前端开发者一起学习和成长。 &#x1f31f;亲爱的朋友们&#x1f31f; 大家好&#xff01;感谢你们一直…

《Tam》论文笔记(下)

3 Method 3.1. The Overview of Temporal Adaptive Module 正如我们在第1节中讨论的&#xff0c;视频数据通常表现出由相机运动和速度变化等因素引起的复杂时间动态。因此&#xff0c;我们的目标是通过引入具有视频特定内核的时间自适应模块 (TAM) 来解决这个问题&#xff0c…

一键自动化博客发布工具,用过的人都说好(infoq篇)

infoq的博客发布界面也是非常简洁的。首页就只有基本的标题&#xff0c;内容和封面图片&#xff0c;所以infoq的实现也相对比较简单。 一起来看看吧。 前提条件 前提条件当然是先下载 blog-auto-publishing-tools这个博客自动发布工具,地址如下&#xff1a;https://github.c…

营收如泡沫,利润如刀片,万辰集团万店梦想下的阴影

&#xff08;作者注&#xff1a;本文建议配乐《泡沫》阅读&#xff01;&#xff09; 从“食用菌第一股”转型为“量贩零食第一股”的首个财年&#xff0c;万辰集团新业务发展迅猛。 财报显示&#xff0c;2023年公司量贩零食业务实现营业收入87.59亿元&#xff0c;同比增长1305…

微火全域运营平台的优缺点分别是什么?

随着全域运营赛道的兴起&#xff0c;微火全域运营平台在市场占有率持续走高&#xff0c;与之相关的各类问题也层出不穷。其中&#xff0c;微火全域运营平台是什么、微火全域运营平台的优缺点等与平台本身相关的问题长期位居话题榜前列。 所谓微火全域运营平台&#xff0c;就是由…

京东手势验证码-YOLO姿态识别+Bézier curve轨迹拟合

这次给老铁们带来的是京东手势验证码的识别。 目标网站&#xff1a;https://plogin.m.jd.com/mreg/index 验证码如下图: 当第一眼看到这个验证码的时候&#xff0c;就头大了&#xff0c;这玩意咋识别&#xff1f;&#xff1f;&#xff1f; 静下心来细想后的一个方案&#xf…

使用apache和htaccess对目录访问设置密码保护配置教程

对目录设置密码保护配置说明 我们有时候访问某些网站的时候&#xff0c;要求输入用户名和密码才能访问。这是为了保护隐私&#xff0c;只让经过许可的人访问。 在本教程中主要介绍两种方法&#xff0c;一种是通过apache httpd.conf配置文件对管理后台目录设置密码保护&#xff…

ESP32引脚入门指南(四):从理论到实践(PWM)

引言 ESP32 作为物联网领域的明星微控制器&#xff0c;除了强大的Wi-Fi和蓝牙功能&#xff0c;还内置了丰富的外设资源&#xff0c;其中就包括高级的PWM&#xff08;脉冲宽度调制&#xff09;功能。本文将深入探讨ESP32的PWM引脚&#xff0c;解析其工作原理&#xff0c;并通过…

分布式与一致性协议之Quorum NWR算法

Quorum NWR算法 概述 不知道你在工作中有没有遇到过这样的事情:你开发实现了一套AP型分布式系统&#xff0c;实现了最终一致性&#xff0c;且业务接入后运行正常&#xff0c;一切看起来都那么美好。 可是突然有同事说&#xff0c;我们要拉这几个业务的数据做实时分析&#xf…

进口原装二手 Keysight86142B 是德86142A 高性能光谱分析仪

进口原装二手 Keysight86142B 是德86142A 高性能光谱分析仪 内置测试应用程序 • 10 pm 波长精度 • 快速双扫法 • 覆盖 S、C 和 L 波段 Keysight 86142B是一款台式光谱分析仪&#xff08;OSA&#xff09;&#xff0c;最适于对功率和波长精度、动态范围和低偏振敏感性都要…

asp.net论坛指南系统

说明文档 运行前附加数据库.mdf&#xff08;或sql生成数据库&#xff09; 主要技术&#xff1a; 基于asp.net架构和sql server数据库 登陆可查看 浏览记录 TA的发布 TA的回复 TA的收藏 TA的点赞 管理员登陆可以查看举报管理 编辑管理 认证审核 帖子置顶申请审核 运行环境…

【数据处理系列】深入理解递归特征消除法(RFE):基于Python的应用

目录 一、递归特征消除法介绍 二、方法介绍 三、导入数据并选择模型 (一)导入数据 (二) 递归特征消除需要选择模型吗 四、RFE方法进行递归特征消除法 五、RFECV方法进行递归特征消除法(建议使用这种方法) 即交叉验证递归特征消除法 (一)参数介绍 (二)python使用RFECV…

我们真的需要5G吗?再读《5G将是一个彻底的失败通信技术》

目录 投入与产出不成正比 《5G将是一个彻底的失败通信技术》 无线通信技术体制 无线通信技术演进 5G需求 移动通信与WiFi 5G之局 未来之路 参考 投入与产出不成正比 2018年开始大规模装备5G设备&#xff0c;因此2018年被称为5G元年。一般5G基站的寿命为8年左右&#…

GeoServer 任意文件上传漏洞分析研究 CVE-2023-51444

目录 前言 漏洞信息 代码审计 漏洞复现 前言 时隔半月&#xff0c;我又再一次地审起了这个漏洞。第一次看到这个漏洞信息时&#xff0c;尝试复现了一下&#xff0c;结果却很不近人意。从官方公布的漏洞信息来看细节还是太少&#xff0c;poc不是一次就能利用成功的。也是当时…

工器具管理(基于若依)

文章目录 前言一、工器具管理项目总览 二、入库功能1. 前端1.1 界面展示1.2 具体操作实现1.3 js文件 2. 后端2.1 工器具信息回显2.2 工器具入库 三、领用功能1. 前端1.1 界面展示1.2 具体实现操作1.3 js文件 2. 后端2.1 工器具信息回显2.2 工器具领用 遇到的问题1. 同一页面展示…

2024最新版守约者二级域名分发系统源码,提供全面的二级域名管理服务

主要功能 二级域名管理&#xff1a;我们的系统提供全面的二级域名管理服务&#xff0c;让您轻松管理和配置二级域名。 下 载 地 址 &#xff1a; runruncode.com/php/19756.html 域名分发&#xff1a;利用我们先进的域名分发技术&#xff0c;您可以自动化地分配和管理域名&…

【教程向】从零开始创建浏览器插件(二)深入理解 Chrome 扩展的 manifest.json 配置文件

第二步&#xff1a;深入理解 Chrome 扩展的 manifest.json 配置文件 上一次我们已经着手完成了一个自己的浏览器插件&#xff0c;链接在这里&#xff1a;我是链接 在本篇博客中&#xff0c;我们将更详细地探讨 Chrome 扩展中的 manifest.json 文件。这个文件是每个浏览器扩展…