代码随想录-刷题第五十七天

42. 接雨水

题目链接:42. 接雨水

思路:本题十分经典,使用单调栈需要理解的几个问题:

  1. 首先单调栈是按照行方向来计算雨水,如图:

    42.接雨水2

  2. 使用单调栈内元素的顺序

    从大到小还是从小到大呢?

    从栈头(元素从栈头弹出)到栈底的顺序应该是从小到大的顺序。

    因为一旦发现添加的柱子高度大于栈头元素了,此时就出现凹槽了,栈头元素就是凹槽底部的柱子,栈头第二个元素就是凹槽左边的柱子,而添加的元素就是凹槽右边的柱子。

    如图:

    42.接雨水4

    关于单调栈的顺序:739. 每日温度中求一个元素右边第一个更大元素,单调栈就是递增的,84.柱状图中最大的矩形求一个元素右边第一个更小元素,单调栈就是递减的。

  3. 遇到相同高度的柱子怎么办。

    遇到相同的元素,更新栈内下标,就是将栈里元素(旧下标)弹出,将新元素(新下标)加入栈中,需要使用最右边的柱子来计算宽度

  4. 栈里要保存什么数值

    栈里就存放下标就行,想要知道对应的高度,通过height[stack.peek()] 就知道弹出的下标对应的高度了。

class Solution {
    public int trap(int[] height) {
        // 找每个柱子左右两边第一个大于该柱子高度的柱子
        int res = 0;
        Deque<Integer> stack = new LinkedList<>();
        stack.push(0);
        
        for (int i = 1; i < height.length; i++) {
            if (height[i] < height[stack.peek()]) {
                // 情况一
                stack.push(i);
            } else if (height[i] == height[stack.peek()]) {
                // 情况二
                stack.pop();
                stack.push(i);
            } else {
                // 情况三
                while (!stack.isEmpty() && height[i] > height[stack.peek()]) {
                    int mid = stack.pop(); // 凹槽的底部,也就是中间位置
                    if (!stack.isEmpty()) {
                        int left = stack.peek();
                        int h = Math.min(height[left], height[i]) - height[mid];
                        int w = i - left - 1; // 注意减一,只求中间宽度
                        res += h * w;
                    }
                }
                stack.push(i);
            }
        }
        return res;
    }
}

双指针解法如下:

class Solution {
    public int trap(int[] height) {
        int n = height.length;
        int res = 0;
        // 数组充当备忘录
        int[] l_max = new int[n];
        int[] r_max = new int[n];
        // 初始化 base case
        l_max[0] = height[0];
        r_max[n - 1] = height[n - 1];
        // 从左向右计算 l_max
        for (int i = 1; i < n; i++)
            l_max[i] = Math.max(height[i], l_max[i - 1]);
        // 从右向左计算 r_max
        for (int i = n - 2; i >= 0; i--)
            r_max[i] = Math.max(height[i], r_max[i + 1]);
        // 计算答案
        for (int i = 1; i < n - 1; i++)
            res += Math.min(l_max[i], r_max[i]) - height[i];
        return res;
    }
}

为了得到两边的最高高度,使用了双指针来遍历,每到一个柱子都向两边遍历一遍,这其实是有重复计算的。把每一个位置的左边最高高度记录在一个数组上(l_max),右边最高高度记录在一个数组上(r_max),这样就避免了重复计算。


84. 柱状图中最大的矩形

题目链接:84. 柱状图中最大的矩形

思路:本题十分适合与接雨水对照来看,接雨水是找每个柱子左右两边第一个大于该柱子高度的柱子,而本题是找每个柱子左右两边第一个小于该柱子高度的柱子。

本题与接雨水最主要的区别在于单调栈中存放元素的顺序不同。其他步骤与接雨水的分析过程相同。

只有栈里从大到小的顺序,才能保证栈顶元素找到左右两边第一个小于栈顶元素的柱子。

所以本题单调栈的顺序正好与接雨水反过来。(栈顶和栈顶的下一个元素以及要入栈的三个元素组成了要求最大面积的高度和宽度

class Solution {
    public int largestRectangleArea(int[] heights) {
        // 找每个柱子左右两边第一个小于该柱子高度的柱子
        int res = 0;
        Deque<Integer> stack = new LinkedList<>();

        // 数组前后各加一个0
        int[] newHeights = new int[heights.length + 2];
        newHeights[0] = 0;
        newHeights[newHeights.length - 1] = 0;
        for (int i = 0; i < heights.length; i++) {
            newHeights[i + 1] = heights[i];
        }
        stack.push(0);

        // 开始遍历
        for (int i = 1; i < newHeights.length; i++) {
            if (newHeights[i] > newHeights[stack.peek()]) {
                // 情况一
                stack.push(i);
            } else if (newHeights[i] == newHeights[stack.peek()]) {
                // 情况二
                stack.pop();
                stack.push(i);
            } else {
                // 情况三
                while (!stack.isEmpty() && newHeights[i] < newHeights[stack.peek()]) {
                    int mid = stack.pop();
                    if (!stack.isEmpty()) {
                        int left = stack.peek();
                        int h = newHeights[mid];
                        int w = i - left - 1;
                        res = Math.max(res, h * w);
                    }
                }
                stack.push(i);
            }
        }
        return res;
    }
}

在 height数组上后,都加了一个元素0, 为什么这么做呢?

首先来说末尾为什么要加元素0?

如果数组本身就是升序的,例如[2,4,6,8],那么入栈之后 都是单调递减,一直都没有走 情况三 计算结果的哪一步,所以最后输出的就是0了。

开头为什么要加元素0?

如果数组本身降序,例如 [8,6,4,2],在 8 入栈后,6 开始与8 进行比较,此时得到 mid(8),right(6),但是得不到 left。因为将 8 弹出之后,栈里没有元素了,那么为了避免空栈取值,直接跳过了计算结果的逻辑。之后又将6 加入栈(此时8已经弹出了),然后就是 4 与栈口元素 8 进行比较,周而复始,那么计算的最后结果result就是0。


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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

自动驾驶轨迹规划之碰撞检测(一)

欢迎大家关注我的B站&#xff1a; 偷吃薯片的Zheng同学的个人空间-偷吃薯片的Zheng同学个人主页-哔哩哔哩视频 (bilibili.com) 目录 1.碰撞检测的意义 2.安全走廊 3 计算几何 4 AABB与OBB 1.碰撞检测的意义 对于自动驾驶汽车或机器人的路径规划&#xff0c;碰撞检测是其…

linux单机部署mysql(离线环境解压即可)

一、下载官网压缩包&#xff08;tar.gz&#xff09; MySQL :: Download MySQL Community Serverhttps://dev.mysql.com/downloads/mysql/根据自己的操作系统发行版本、位数、gclib版本、mysql版本来选择对应的压缩包 比如我是 linux系统debian10&#xff08;官网只有linux ge…

PaddleDetection学习1——使用Paddle-Lite在 Android 上实现实时的目标检测功能

在 Android 上使用Paddle-Lite实现实时的目标检测功能 1 环境准备1.1 安装Android Studio1.1.1 安装JAVA JDK1.1.2 Android Studio 安装步骤1.1.3 Android Studio 配置NDK 1.2 Android 手机 2 部署步骤2.1 下载Paddle-Lite-Demo2.2 打开 yolo_detection_demo项目2.2.1 修改buil…

001基于51单片机的弹丸测速系统设计

基于51单片机的弹丸测速系统设计[proteus仿真] 速度检测系统这个题目算是课程设计和毕业设计中常见的题目了&#xff0c;本期是一个基于51单片机的自行车测速系统设计 需要的源文件和程序的小伙伴可以关注公众号【阿目分享嵌入式】&#xff0c;赞赏任意文章 2&#xffe5;&am…

[网络安全] NDS部署与安全

一、NDS服务器 &#xff08;域名系统Domain Name System&#xff09; 二、域名组成&#xff1a; 1.域名组成概述 如“www.baidu.com” 是个域名&#xff0c;严格意义来讲"baidu.com"为域名(全球唯一), www为主机名. “主机名.域名”称为完全限定域名&#xff08;F…

133基于matlab的智能微电网粒子群优化算法

基于matlab的智能微电网粒子群优化算法&#xff0c;输出微型燃气轮机、电网输入微网运行计划、储能运行计算。程序已调通&#xff0c;可直接运行。 133智能微电网粒子群优化算法 (xiaohongshu.com)

鸿蒙使用 axios

1、已安装ohpm&#xff0c;可参考上一篇 2、回到项目的根目录执行 ohpm install ohos/axios 安装成功后&#xff0c;查看项目的package 3、开放网络权限 在模块的module.json5中添加权限 "module": {"requestPermissions": [{"name": "…

一篇搞定CMake入门:让你轻松学会C++项目构建!

&#x1f608;「CSDN主页」&#xff1a;传送门 &#x1f608;「Bilibil首页」&#xff1a;传送门 &#x1f608;「动动你的小手」&#xff1a;点赞&#x1f44d;收藏⭐️评论&#x1f4dd; 文章目录 CMake专栏介绍CMake基础篇CMake核心篇CMake高级篇CMake实战篇 CMake专栏介绍 …

C++初入(四)

1.万能头文件 #include <bits/stdc.h> 里面包含了大量我们日常所需的头文件&#xff0c;如果使用它&#xff0c;我们就可以减少大量时间去写头文件&#xff0c;但是其实在平常练习和实际运用中&#xff0c;该头文件几乎没有实际价值&#xff0c;原因&#xff1a;1.里面…

【Python】线程threading与GUI窗口tkinter结合应用

Python的threading模块是一个强大的工具&#xff0c;它提供了高级别的线程编程接口。通过这个模块&#xff0c;Python程序员可以在应用程序中实现多线程并发执行。 线程&#xff08;Thread&#xff09;是程序执行流的最小单元&#xff0c;被包涵在进程之中&#xff0c;是进程中…

GitHub图床搭建

1 准备Github账号 如果没有Github账号需要先在官网注册一个账号 2 创建仓库 在github上创建一个仓库&#xff0c;随便一个普通的仓库就行&#xff0c;选择公共仓库 并且配置github仓库的pages&#xff0c;选择默认访问的分支及默认路径 3 github token获取 github token创…

线下安防监控店如何制作小程序商城?开通线上销售渠道

线下安防监控店可以通过制作小程序商城来开通线上销售渠道&#xff0c;为顾客提供更方便快捷的购物体验。下面介绍一种简单的制作小程序商城的方法。 首先&#xff0c;登录【乔拓云】网后台&#xff0c;进入【商城】管理页面。在该页面中&#xff0c;找到并点击【小程序商城】模…

第一次开发基于SpringBoot的Java应用

第一次开发基于SpringBoot的Java应用 一、 方式1&#xff1a;IDEA创建New Project Spring Boot官方文档的Getting Started1、IDEA创建New Project2、Spring Boot官方文档的Getting Started2.1 Creating the POM &#xff08;实际是&#xff0c;更新pom.xml&#xff09;2.2 Add…

如何选择适合的乔拓云小程序付费服务

在数字化时代&#xff0c;微信小程序已经成为商家与客户互动的重要平台。乔拓云小程序作为一款便捷的微信小程序&#xff0c;不仅提供免费的基本功能&#xff0c;还为商家提供了多种付费增值服务和广告投放选择&#xff0c;以满足不同需求。本文将为您揭秘乔拓云小程序的费用明…

rabbitmq基础教程(ui,java,springamqp)

概述&#xff1a;安装看我上篇文章Docker安装rabbitmq-CSDN博客 任务一 创建一个队列 这样创建两个队列 在amq.fanout交换机里面发送数据 模拟发送数据 发送消息&#xff0c;发现一下信息&#xff1a; 所以得出理论&#xff0c;消息发送是先到交换机&#xff0c;然后由交换机…

部署配置zabbix监控平台(server端)

目录 引言&#xff1a;明人不说暗话&#xff0c;分享一下部署配置zabbix监控平台的详细过程 1.进入官网 2.进入下载页面选择需要下载的版本信息 &#xff08;案例zabbix5.0&#xff09; 划到下面有安装的过程&#xff0c;下面我详细讲解一下这些步骤 3、安装Zabbix存储库 …

Tide Quencher 7.1WS azide,TQ7.1WS N3,适用于多种荧光物质的分析

您好&#xff0c;欢迎来到新研之家 文章关键词&#xff1a;Tide Quencher 7.1WS 叠氮&#xff0c;TQ7.1WS 叠氮&#xff0c;Tide Quencher 7.1WS azide&#xff0c;TQ7.1WS N3&#xff0c;TQ7.1WS azide&#xff0c;Tide Quencher 7.1WS N3 一、基本信息 产品简介&#xff1…

【揭秘AI】穿越时光隧道,探秘AI起源与发展01

算盘 被誉为世界上最古老的计算机之一&#xff0c;是一种手动操作的计算工具&#xff0c;起源于中国。它主要由框、梁和珠子组成&#xff0c;通过移动珠子在档位上的位置来进行加减乘除运算。算盘的发明时间可以追溯到公元前或公元初期&#xff0c;据历史记载&#xff0c;东汉…

vue实现 marquee(走马灯)

样式 代码 <div class"marquee-prompt"><div class"list-prompt" refboxPrompt><span v-for"item in listPrompt" :title"item" class"prompt">{{item}}</span></div> </div>data() {…

【IAP】核心开发流程

最近做了IAP U盘升级模块开发&#xff0c;总结下IAP基本开发流程&#xff0c;不深入讨论原理。 详细原理参考 首先需要知道我们需要把之前的APP区域拆一块出来做BOOT升级程序区域。 以STM32F103为例&#xff0c;0x08000000到0x0807FFFF为FLASH空间&#xff0c;即上图代码区域…