力扣接雨水

news2025/1/9 1:10:58

给定 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

 动态规划:

class Solution {
    public int trap(int[] height) {
        int len = height.length;
        
        // 如果数组长度为0,返回0
        if(len == 0){
            return 0;
        }

        // 创建一个数组用于存储每个位置左侧的最大高度
        int[] leftMax = new int[len];
        for(int i = 1; i < len; i++){
            // 更新当前点的左侧最大高度
            leftMax[i] = Math.max(height[i-1], height[i]);
        }

        // 创建一个数组用于存储每个位置右侧的最大高度
        int[] rightMax = new int[len];
        for(int i = len-2; i >= 0; i--){
            // 更新当前点的右侧最大高度
            rightMax[i] = Math.max(height[i], height[i+1]);
        }

        int ans = 0;
        // 计算每个位置能够存储的水量
        for(int i = 0; i < len; i++){
            ans += Math.min(leftMax[i], rightMax[i]) - height[i];
        }
        
        // 返回能够存储的总水量
        return ans;
    }
}

单调栈解决

import java.util.Stack;

class Solution {
    public int trap(int[] height) {
        // 初始化总雨水量为0
        int totalWater = 0;
        // 创建一个栈用于存储数组索引
        Stack<Integer> stack = new Stack<>();
        
        // 遍历每个高度
        for (int i = 0; i < height.length; i++) {
            // 当栈非空且当前高度大于栈顶所指的高度时
            while (!stack.isEmpty() && height[i] > height[stack.peek()]) {
                // 取出栈顶的高度索引
                int top = stack.pop();
                
                // 如果栈为空,跳出循环
                if (stack.isEmpty()) {
                    break;
                }
                
                // 计算当前柱子的宽度
                int distance = i - stack.peek() - 1;
                // 计算能形成的水位高度差
                int boundedHeight = Math.min(height[i], height[stack.peek()]) - height[top];
                // 计算当前能积的水量并加到总水量中
                totalWater += distance * boundedHeight;
            }
            // 将当前索引入栈
            stack.push(i);
        }
        
        // 返回总雨水量
        return totalWater;
    }
}

工作原理

  1. 单调递减栈:栈中存储的是高度数组的索引。栈内元素对应的高度从栈底到栈顶是非递增的。
  2. 遍历高度数组:对于每一个高度,若其大于栈顶元素所指的高度(即找到一个可能的凹槽),则计算当前凹槽的水量。
  3. 水量计算
    • 宽度:凹槽宽度为当前索引 i 与栈顶下一个元素的索引之差再减去 1。
    • 高度:水位高度差为 min(当前高度, 栈顶下一个高度) - 栈顶高度
  4. 累加水量:将计算出的水量累加到总水量中。

在计算接雨水的过程中,水的高度取决于柱子之间的最低高度。具体来说,水只能被较矮的柱子挡住。因此,关键在于找到最低的柱子,并根据它来计算可能存储的水量。

class Solution {
    public int trap(int[] height) {
        int len=height.length;
        int left=0,right=len-1;
        int leftMax=0,rightMax=0;
        int ans=0;

        while(left<=right){
            leftMax=Math.max(leftMax,height[left]);
            rightMax=Math.max(rightMax,height[right]);
            if(height[left]<height[right]){
                ans+=leftMax-height[left];
                left++;
            }else{
                ans +=rightMax-height[right];
                right--;
            }
        }
        return ans;
    }
}

判断逻辑

  1. 水量计算基础

    • 对于 height[left] < height[right] 的情况,由于 leftMax 是从左侧移动过程中遇到的最大高度,而 rightMax 是从右侧移动过程中遇到的最大高度,因此:
      • 当前柱子 height[left] 左侧的最大高度 leftMax 是可靠的。
      • 但是,右侧的最大高度 rightMax 还可能会更新。因此,此时计算 left 位置的积水量是安全的。
  2. 为什么选择较小的高度

    • 如果 height[left] < height[right],意味着在当前位置 left,其右侧有更高的柱子。这个较高的柱子可以帮助挡住雨水。因此可以确定 leftMax 是最小的限制条件,用它来计算当前位置可能存储的水量是安全的。
    • 如果 height[left] >= height[right],那么右侧柱子在此时成为决定因素,左侧的 leftMax 没有影响,应该通过 rightMax 计算右侧的水量。

例子说明

假设 height[left] = 2height[right] = 5

  • left 侧低于 right:可以确定在左侧 left 柱子能容纳的水量只取决于 leftMax。因此,将 left 向右移动并计算 leftMax - height[left]

  • 如果反过来:如果左侧高于或等于右侧,则右侧可能会积水,因此移动 right 向左并计算 rightMax - height[right]

总结

这一判断的核心在于:

  • 小于:左侧可能有积水,计算左侧。
  • 大于等于:右侧可能有积水,计算右侧。

初始状态下的 right 指针

  • right 指针初始位置:它从数组的最右端开始。
  • left 指针初始位置:它从数组的最左端开始。

初始比较:height[left] < height[right]

在算法的开始阶段,我们用 height[left] < height[right] 来判断接下来的行动。虽然 right 一开始位于数组的最右边,但这并不影响算法的正确性,原因如下:

  1. rightMax 的初始化

    • 初始时,rightMax 会等于 height[right]。因为 right 指针在最右端,所以 rightMax 一开始就是数组最右边的那个高度。
    • 随着 right 指针向左移动,rightMax 会逐渐更新为更大的值,直到遍历完所有右边的柱子。
  2. 初始状态的判断

    • 在开始时,算法将 leftright 的柱子高度进行比较。
    • 如果 height[left] < height[right],说明左边的柱子比右边矮。在这种情况下,右边更高的柱子可以“挡住”水,因此左边柱子上方可能会有积水,这时候左边的积水高度是可以确定的,所以移动 left 指针并计算水量。
    • 如果 height[left] >= height[right],算法会移动 right 指针。此时,不会计算 left 指针位置的积水,而是继续查看右边的柱子是否可能形成积水。
  3. 意义在于确定安全的水量

    • 通过比较 height[left]height[right],算法确保了在当前位置计算水量时,有足够的信息保证水量是准确的。
    • rightMaxleftMax 在算法执行过程中不断更新,确保算法总是在安全的条件下进行计算。

实际意义

即使 right 指针最开始位于最右边,这个初始比较也有意义,因为它为整个算法奠定了基础。我们可以通过这个初始比较,确保在移动 leftright 指针时,计算的积水量是正确且安全的。

举个例子

假设 height 数组为 [1, 0, 2, 1, 0, 1, 3]leftright 初始分别在位置 06

  • left 开始为 1right 开始为 3
  • 第一次比较时,height[left] = 1height[right] = 3,显然 1 < 3,我们可以放心地移动 left 指针,因为左边的积水高度确定不会超过 leftMax

总之,这一步比较对于算法的正确性和水量计算至关重要,即使 right 指针最初处于最右边,也依然有效且必要。

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

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

相关文章

html css网页制作

​ 大家好&#xff0c;我是程序员小羊&#xff01; 前言&#xff1a; HTML 和 CSS 是制作网页的基础。HTML 用于定义网页的结构和内容&#xff0c;CSS 用于设计网页的样式和布局。以下是一个详细的网页制作成品教程&#xff0c;包括 HTML 和 CSS 的基础知识&#xff0c;及如何…

MySQL基础(7)- 多表查询

目录 一、笛卡尔积的错误与正确的多表查询 1.出现笛卡尔积错误 2.正确的多表查询&#xff1a;需要有连接条件 3.查询多个表中都存在的字段 4.SELECT和WHERE中使用表的别名 二、等值连接vs非等值连接、自连接vs非自连接 1.等值连接 vs 非等值连接 2.自连接 vs 非自连…

安卓逆向(之)真机root(红米手机)

概览&#xff1a; 1, 手机解锁 2, 下载官方系统包&#xff0c;推荐线刷包,取出镜像文件 3, magisk工具修补 官方系统包 4, adb&#xff1a;命令对手机刷 root 5, 完成 6, 小米手机解锁 点击 小米手机解锁OEM官方教程 记得数据线连接手机电脑 工具下载 点击 下载adb(电脑操作…

进程间通信-进程池

目录 理解​ 完整代码 完善代码 回收子进程&#xff1a;​ 不回收子进程&#xff1a; 子进程使用重定向优化 理解 #include <iostream> #include <unistd.h> #include <string> #include <vector> #include <sys/types.h>void work(int rfd) {…

Windows下使用cmake编译OpenCV

Windows下使用cmake编译OpenCV cmake下载OpenCV下载编译OpenCV cmake下载 下载地址&#xff1a;https://cmake.org/download/ 下载完成&#xff0c;点击选择路径安装即可 OpenCV下载 下载地址&#xff1a;https://github.com/opencv/opencv/releases/tag/4.8.1因为我们是编译…

2024软件测试需要具备的技能(软技能硬技能)

软件测试的必备技能 在往期的文章分享了很多的面试题&#xff0c;索性做一个转型。从零基础开始讲解&#xff0c;结合面试题来和大家一起学习交流软件测试的艺术。 第一个是专业技能&#xff0c;也叫硬技能。 第二个叫做软技能。 我们在上一篇文章中讲到了软件测试流程的5个…

ChatGPT在论文写作领域的应用:初稿设计

学境思源&#xff0c;一键生成论文初稿&#xff1a; AcademicIdeas - 学境思源AI论文写作 学术论文写作中&#xff0c;内容清晰、结构合理的初稿至关重要。通过 ChatGPT&#xff0c;写作者可以快速生成内容框架、明确研究问题&#xff0c;并优化表达方式。不仅提高了写作效率&…

笔记整理—内核!启动!—kernel部分(1)驱动与内核的关系

首先&#xff0c;恭喜完成了uboot部分的内容整理&#xff0c;其次补充一点&#xff0c;uboot第一部分和第二部分的工作不是一定的&#xff0c;在不同的版本中&#xff0c;可能这个初始化早一点&#xff0c;那个的又放在了第二部分&#xff0c;版本不同&#xff0c;造成的工作顺…

滑动窗口——632. 最小区间

最近在抽时间写LC上的一个专栏——2024春招冲刺百题计划。挑着做&#xff0c;做了几道和滑动窗口相关的题目&#xff0c;632. 最小区间&#xff0c;LC上标记为困难&#xff0c;第一次写完全没有思考&#xff0c;参考了别人写的答案茅塞顿开&#xff0c;特此记录以鞭策自己学习。…

Android perfetto 简介

Android perfetto 简介 使用 perfetto 工具&#xff0c;您可以通过 Android 调试桥 (adb) 在 Android 设备上收集性能信息。使用 adb shell perfetto ... 命令调用 perfetto 工具。 perfetto 从您的设备上收集性能跟踪数据时会使用多种来源&#xff0c;例如&#xff1a; 使用…

5、const修饰类型和变量

const修饰类型和变量 一、const常量一些注意点1、声明时必须同时初始化2、不可更改3、与宏常量的区别 二、const修饰指针1、常量指针constant pointer2、常指向指针pointer-to-constant pointer 一、const常量一些注意点 1、声明时必须同时初始化 #include <iostream> …

框架template初识

框架初识 框架就是一个别人帮我们搭好的舞台&#xff0c;造好了很多现成的工具供我们使用&#xff0c;让开发过程更快速、简洁。 Gin框架介绍 Gin 是一个用 Go (Golang) 编写的 HTTP Web 框架。 Gin是一个用Go语言编写的web框架。它是一个类似于martini 但拥有更好性能的API…

企业网银登录提示请确认您已插入工商银行U盾证书的解决方法

昨天受人之托帮小企业财务解决上网银的问题 因为不是专业做这个的&#xff0c;所以只能安装“常识”行事&#xff0c;但结果实在是令人意想不到。 排错的步骤&#xff1a; 同一台电脑上尝试不同浏览器&#xff0c;发现360浏览器的接受度相当普遍&#xff1b;给U盾换不同的连接…

抖音引流脚本工具,实现自动化引流,解放大家双手

抖音引流脚本工具,实现自动化引流,解放大家双手 #获客引流 推荐阅读&#xff1a; 百收网SEO引流脚本软件不断更新&#xff08;推广全集教程&#xff09;https://www.bsw80.com/post/460.html 我们这篇文章的话&#xff0c;来去给大家说一下这个抖音这个同城评论&#xff0c;…

探索 RAD:5 个最佳实践案例解析

天下武功&#xff0c;唯快不破&#xff01;应用开发&#xff0c;唯速称王&#xff01; 在当今快速发展的科技环境中&#xff0c;企业面临的挑战不断升级。传统的应用开发方法往往因其复杂的流程和较长的开发周期而无法满足快速变化的市场需求。在这种背景下&#xff0c;快速应…

【阿里云】个人认证与公司认证

个人认证和企业认证的区别 更新时间&#xff1a;2024-05-20 09:32:52 本文档主要介绍个人认证账号和企业认证账号的区别。 账号实名认证分为个人实名认证和企业实名认证。 个人账号认证&#xff0c;请选择认证类型为 个人&#xff0c;支持个人支付宝授权认证和个人扫脸认证。…

如何免费将视频转换为 MP4?将视频转换为 MP4 的 5 种方法

您知道如何免费将不受支持的视频格式转换为 MP4 吗&#xff1f; 您可以轻松地在视频共享网站和社交应用上访问各种视频。从网站下载视频但无法使用媒体播放器播放是很常见的事。如何将视频转换为 MP4以便更好地播放&#xff1f; 事实上&#xff0c;市场上有很多视频音频转换工…

【Python 千题 —— 算法篇】字符统计

Python 千题持续更新中 …… 脑图地址 &#x1f449;&#xff1a;⭐https://twilight-fanyi.gitee.io/mind-map/Python千题.html⭐ 题目背景 在编程中&#xff0c;对字符串的字符统计是一个常见任务。这在文本处理、数据分析、词频统计、自然语言处理等领域有广泛应用。无论…

PS插件DR5至臻高级版下载安装教程Photoshop美颜美白牙齿磨皮使用插件百度网盘分享

DR5至臻高级版PS插件DR5至臻高级版下载安装教程Photoshop美颜美白牙齿磨皮使用插件百度网盘分享链接地址可以对眼睛、眉毛、嘴唇等五官进行精细调整&#xff0c;如增强眼睛的明亮度和清晰度&#xff0c;使眉毛更加立体&#xff0c;嘴唇更加饱满可以快速有效地去除人像照片中的瑕…

使用 EMQX 开源版的 Webhook 机制处理消息并存储数据

1、前言 EMQX 是一款强大的开源 MQTT 消息代理&#xff0c;它支持大量的连接和高吞吐量&#xff0c;适用于各种物联网应用。Webhook 是 EMQX 提供的扩展功能之一&#xff0c;用于将消息推送到外部的 HTTP 服务。在本文中&#xff0c;我们将介绍如何使用 EMQX 开源版的 Webhook …