单调栈【2023年最新】

做题的时候看到了单调栈,但是不知道是个什么玩意,记录一下吧。

单调栈含义

单调栈是一种特殊的数据结构,用于解决一些与单调性相关的问题。它的基本含义是在栈的基础上,维护一个单调递增或单调递减的栈。

在单调递增栈中,栈内元素从栈底到栈顶是递增有序的,而在单调递减栈中,栈内元素从栈底到栈顶是递减有序的。

单调栈的基本使用是通过维护栈内元素的单调性,来解决一些与单调性相关的问题。常见的应用场景包括:

  1. 下一个更大元素:给定一个数组,对于每个元素,找到它右边第一个比它大的元素。
  2. 下一个更小元素:给定一个数组,对于每个元素,找到它右边第一个比它小的元素。
  3. 最大矩形面积:给定一个二维矩阵,求其中全为1的最大矩形的面积。

使用单调栈解决这些问题的基本思路是,遍历数组或矩阵中的元素,将元素依次入栈,并在入栈时维护栈内元素的单调性。当遇到一个元素破坏了栈内元素的单调性时,可以根据问题的要求进行相应的处理,然后将该元素入栈。

通过这种方式,可以在O(n)的时间复杂度内解决一些与单调性相关的问题,其中n是数组或矩阵的大小。

看到个题目,昨天,想自己用单调栈做出来,但是没做出来,上网看了下有一些解法,但是都存在问题?然后叫ChatGPT写了一个,感觉能用,也测试了一下,确实可以,但是为什么可以这样做,还是有点懵,既然不懂那就死记硬背吧。

视野总和

描叙:有n个人站队,所有的人全部向右看,个子高的可以看到个子低的发型,给出每个人的身高,问所有人能看到其他人发现总和是多少。
输入:4 3 7 1
输出:2

解释:个子为4的可以看到个子为3的发型,个子为7可以看到个子为1的身高,所以1+1=2
思路:观察题之后,我们发现实际上题目转化为找当前数字向右查找的第一个大于他的数字之间有多少个数字,然后将每个结果累计就是答案。

    public static int calculateFieldSum(int[] heights) {
        int n = heights.length;
        Stack<Integer> stack = new Stack<>();
        int sum = 0;

        for (int i = 0; i < n; i++) {
            while (!stack.isEmpty() && heights[i] >= heights[stack.peek()]) {
                stack.pop();
            }
            sum += stack.size();
            stack.push(i);
        }

        return sum;
    }

柱状图中最大的矩形

这一题,自己先用普通的栈去实现,但是发现只能解决部分问题,存在局限性(也有可能是能力不足哈哈不会写)然后看了答案以后可以使用单调栈来实现。这一题的思路其实很简单,但是如果暴力的话肯定会超时的而且比较麻烦,所以可以用单调栈来解决,设计一个单调递增栈来解决问题,一旦出现有元素小于栈顶,则开始计算目前的矩形最大面积是多少。不过这一题里面加了两个零边界值,目前刚学,没有发现这两个零的特殊作用,查阅资料后才恍然大悟:

在这个算法中,将原始数组 heights 的长度加2,并在新数组 m 的开头和末尾分别设置为0,是为了处理边界情况。

在解决最大矩形面积问题时,需要考虑到矩形的边界情况。通过在 m 数组的开头和末尾添加高度为0的元素,可以确保栈中的元素都能找到对应的左边界和右边界。

具体来说,在遍历 m 数组时,当遇到一个元素小于栈顶元素时,表示栈顶元素的右边界确定,可以计算以栈顶元素为高度的矩形的面积。如果没有添加开头和末尾的0元素,那么在某些情况下,栈中的元素可能无法找到对应的左边界或右边界,导致计算面积时出现错误。

因此,通过在 m 数组的开头和末尾添加高度为0的元素,可以确保栈中的元素都能找到对应的左边界和右边界,从而正确计算最大矩形面积。

比如说:2 1 5 6 2 3 这个数据

我们如果不设置两个0的话,那么我们数据遍历完后,栈中其实还是有数据的。如果栈中的数据是最大值的话,因为我们最后设置了个0,又因为本题数据0 <= heights[i] <= 10000,所以最后一次计算的时候,也会把剩余的栈中元素再计算他们的最大矩形值。

题目如下:

代码如下,开袋即食:

class Solution {
    public int largestRectangleArea(int[] heights) {
        if(heights.length==1) return heights[0];
        int res = 0;
        Stack<Integer> s = new Stack<>();
        int[] newH = new int[heights.length+2];
        newH[0] = 0;
        newH[heights.length+1]=0;

        for(int i = 1 ; i<heights.length+1;i++){
            newH[i] = heights[i-1];
        }
        for(int i = 0;i<newH.length;i++){
            while(!s.isEmpty()&&newH[i]<newH[s.peek()]){
                int p = s.pop();
                int h = newH[p];
                int leftIndex = s.peek();
                int w = i-leftIndex-1;
                res = Math.max(res,h*w);
            }
            s.push(i);
        }
        return res;
    }
}

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

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

相关文章

SpringCloud-Gateway无法使用Feign服务(2021.X版本)

Spring Cloud Gateway 2021.x版本&#xff0c;无法使用Feign调用其他服务接口。 问题原因&#xff1a; 在官网的 issue 里面找到了相关的问题。 How to call another micro-service on GatewayFilterFactory ? Issue #1090 spring-cloud/spring-cloud-gateway GitHubHel…

QT QSplitter

分裂器QSplitter类提供了一个分裂器部件。和QBoxLayout类似&#xff0c;可以完成布局管理器的功能,但是包含在它里面的部件,默认是可以随着分裂器的大小变化而变化的。 比如一个按钮放在布局管理器中,它的垂直方向默认是不会被拉伸的,但是放到分裂器中就可以被拉伸。还有一点不…

OV5640的参数与配置方法

分辨率和速率&#xff08;FPS&#xff09; 寄存器配置 I/O 板的驱动能力和方向控制 system clock control OV5640 PLL 允许输入时钟频率范围为 6~27 MHz&#xff0c;最大 VCO 频率为 800 MHz。 MipiClk 用于 MIPI&#xff0c;SysClk 用于图像信号处理 (ISP) 模块的内部时钟。 …

TensorFlow(1):深度学习的介绍

1 深度学习与机器学习的区别 学习目标&#xff1a;知道深度学习与机器学习的区别 区别&#xff1a;深度学习没有特征提取 1.1 特征提取方面 机器学习的特征工程步骤是要靠手动完成的&#xff0c;而且需要大量领域专业知识深度学习通常由多个层组成&#xff0c;它们通常将更简…

Redis系列之实现分布式自增主键

软件环境 JDK 1.8 SpringBoot 2.2.1 Maven 3.2 Mysql 8.0.26 redis 6.2.14 Mybatis Plus 3.4.3.4 开发工具 IntelliJ IDEA smartGit 一、实现原理 使用Redis来实现分布式的主键自增主要是依赖于Redis的INCR命令&#xff0c;调用INCR命令的对应key&#xff0c;其数值…

centos7部署Canal与Canal集成使用

1、简介 canal [kə’nl]&#xff0c;译意为水道/管道/沟渠&#xff0c;主要用途是基于 MySQL 数据库增量日志解析&#xff0c;提供增量数据订阅和消费 早期阿里巴巴因为杭州和美国双机房部署&#xff0c;存在跨机房同步的业务需求&#xff0c;实现方式主要是基于业务 trigge…

Flink架构

1、Apache Flink集群的核心架构&#xff1a; 1、client&#xff08;作业客户端&#xff09;&#xff1a;提交任务的地方叫做客户端 2、JobManager&#xff08;作业管理器&#xff09;&#xff1a;作用是用于管理集群中任务 3、TaskManager&#xff08;任务管理器&#xff09;&a…

k8s 1.28安装

容器运行时&#xff0c;containerd 按照官方的指导&#xff0c;需要安装runc和cni插件&#xff0c;提示的安装方式&#xff0c;有三种&#xff1a; 二进制安装包源码apt-get 或 dnf安装 我们这里选用第三种&#xff0c;找到docker官方提供的安装方式 ubuntu-containerd # A…

Elasticsearch:使用你的 RAG 来进行聊天

什么是人工智能中的检索增强生成&#xff08;RAG&#xff09;&#xff1f; 检索增强生成 (RAG)&#xff0c;与你的文档聊天的超级英雄&#xff0c;架起信息检索和文本生成世界的桥梁&#xff01; 这就像福尔摩斯和莎士比亚联手解决需要大量知识的复杂任务。 RAG 突然介入&…

网络编程套接字(3)——协议定制 | 序列化与反序列化

文章目录 一.认识“协议”1.协议的概念2.结构化数据的传输3.序列化和反序列化 二. 网络版计算器1.服务端2.协议定制(1) 网络发送和读取的正确理解(2) 协议定制的问题 3.客户端4.代码 三.Json实现序列化反序列化1.简单介绍2.使用 一.认识“协议” 1.协议的概念 协议&#xff0c…

Pytest插件

官方文档&#xff1a;API Reference — pytest documentation BaseReport 定义Case结果输出 >>> from _pytest.reports import TestReport >>> test TestReport(1,1,1,pass,,running) >>> print(dir(test)) [__annotations__, __class__, __delatt…

02-MySQL-基础-增删改查

一、DDL 定义数据库对象&#xff08;数据库&#xff0c;表&#xff0c;字段&#xff09; ①&#xff1a;数据库操作 01. 查询 1. 查询所有数据库 show databases;2. 查询当前使用的数据库 SELECT database();02. 使用 USE sys;03. 创建 CREATE DATABASE [IF NOT EXISTS]数据…

自动化测试(Java+eclipse)教程

webdriver环境配置 1.下载chromedriver到本地&#xff08;一定要选择和自己浏览器相对应的版本chromedriver下载地址&#xff09; 2.加入到环境变量path中 webdriver工作原理 创建web自动化测试脚本 1.Maven项目创建 File->New->project->(搜索maven)选择maven pr…

JavaScript客户端操作

BOM(browser object model)是浏览器对象模型的简称&#xff0c;被广泛应用于Web开发中&#xff0c;主要用于对客户端浏览器的管理。BOM的概念比较古老&#xff0c;但是一直没有被标准化&#xff0c;不过各主流浏览器均支持BOM&#xff0c;都遵守最基本的规则和用法&#xff0c;…

Dcoker学习笔记(一)

Dcoker学习笔记一 一、 初识Docker1.1 简介1.2 虚拟机和docker的区别1.3 Docker架构1.4 安装Docker&#xff08;Linux&#xff09; 二、 Dcoker基本操作2.1 镜像操作2.2 容器操作练习 2.3 数据卷volume&#xff08;容器数据管理&#xff09;简介数据卷语法数据卷挂载 2.4 自定义…

【Node.js入门】1.1Node.js 简介

Node.js入门之—1.1Node.js 简介 文章目录 Node.js入门之—1.1Node.js 简介什么是 Node.js错误说法 Node.js 的特点跨平台三方类库自带http服务器非阻塞I/O事件驱动单线程 Node.js 的应用场合适合用Node.js的场合不适合用Node.js的场合弥补Node.js不足的解决方案 什么是 Node.j…

前端缓存机制——强缓存、弱缓存、启发式缓存

强缓存和弱缓存的主要区别是主要区别在于缓存头携带的信息不同。 强缓存&#xff1a; 浏览器发起请求&#xff0c;查询浏览器的本地缓存&#xff0c;如果找到资源&#xff0c;则直接在浏览器中使用该资源。若是未找到&#xff0c;或者资源已过期&#xff0c;则浏览器缓存返回未…

Java进阶(JVM调优)——JVM调优参数 JDK自带工具使用 内存溢出和死锁问题案例 GC垃圾回收

前言 JVM作为Java进阶的知识&#xff0c;是需要Java程序员不断深度和理解的。 本篇博客介绍JVM调优的相关知识&#xff0c;给出了一个demo案例&#xff0c;介绍了JVM调优的主要参数&#xff1b;介绍了jdk自带的jvm分析工具的使用&#xff1b;给出了一个内存溢出的调优场景&am…

Unity中Shader再议ATTENUATION

文章目录 前言一、实现实时阴影的投射1、直接复制之前实现投射阴影的Pass 二、实现实时阴影的接受&#xff0c;同时实现光照衰减1、在 v2f 中使用这个2、在 顶点着色器 中使用这个3、在 片元着色器 中使用这个 前言 在之前文章中&#xff0c;实现了 Global Illumination 的直接…

leetcode经典面试150题---5.多数元素

目录 题目描述 前置知识 代码 方法一 排序法 思路 实现 复杂度 方法二 哈希表 思路 实现 题目描述 给定一个大小为 n 的数组 nums &#xff0c;返回其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。 你可以假设数组是非空的&#xff0c;并且给…