03链表+栈+队列(D2_栈)

目录

讲解一:栈

一、基本介绍

二、代码示例

------------------------------

讲解二:单调栈

一、基本介绍

二、适用场景

三、情形示例

1. 寻找左边第一个小于它的数

2. 寻找左边第一个小于它的数的下标

3. 寻找右边第一个大于它的数

4. 寻找右边第一个大于它的数的下标

七、知识小结


讲解一:栈

一、基本介绍

栈(stack)是一个有序线性表,只能在表的一端(称为栈顶,top)执行插人和删除操作,后插入的元素

将是第一个被删除。所以,栈也称为后进先出(LastInFirstOut,LIFO)或先进后出(First In Last

Out,FILO)线性表。

  • 一个称为入栈(push),表示在栈中插入一个元素;
  • 另一个称为出栈(pop),表示从栈中删除一个元素。

试图对一个空栈执行出栈操作称为下溢(underflow);

试图对一个满栈执行人栈操作称为溢出(overflow)。

通常,溢出和下溢均认为是异常。

二、代码示例

示意图

实现

  • 使用数组实现的叫静态栈
  • 使用链表实现的叫动态栈

------------------------------

讲解二:单调栈

一、基本介绍

🍐单调栈分为单调递增栈和单调递减栈,通过使用单调栈我们可以访问到最近一个比它大(小)

的元素。

🍊 单调递增栈:单调递增栈就是从栈底到栈顶数据是依次递增,通常是寻找某方向第一个比它小

的元素。

🍊 单调递减栈:单调递减栈就是从栈底到栈顶数据是依次递减,通常是寻找某方向第一个比它大

二、适用场景

什么情况适合用单调栈来解决实际问题呢?

通常是在数组中需要通过比较前后元素的大小关系来找最近的比它大(小)的元素问题时,可以使

用单调栈进行求解。

三、情形示例

1. 寻找左边第一个小于它的数

题目描述: 给定一个长度为 n ≤ 10 ^5 的数组 a,输出每个数左边第一个比它小的数,如果不存在则输出 − 1。

【常规思路】

双重循环来做,第一重循环枚举每个数,第二重循环找出指定区间类第一个满足条件的数。

然而这种做法的复杂度是O(n^2)利用单调栈,我们可以将复杂度降低至O(n)。

  • 在指针 i 从左往右遍历的过程中,我们可以用一个栈来保存 i 左边的所有元素(不包括i指向的元素),下标越大的元素越接近栈顶,
    下标越小的元素越接近栈底。
  • 每次我们访问栈顶,只要栈顶元素大于等于 a [ i ],我们就将栈顶元素弹出,直至栈顶元素小于 a [ i ],此时输出栈
    顶元素并将 a [ i ] 压入栈中。 由于栈中保存了 i 左边的所有元素,所以只要有答案,则答案一定在栈中。
  • 由于每个元素一定会被压入一次且至多弹出一次,因此操作次数至多是2n,故总时间复杂度为O(n)。

Java代码如下:

public class Main {
    static int N = (int) (1e5 + 10);
    static int[] a = new int[N], ans = new int[N];
    static Deque<Integer> stack = new LinkedList<>();
    static StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));

    public static void main(String[] args) throws IOException {
        in.nextToken();
        int n = (int) in.nval;
        for (int i = 0; i < n; i++) {//存数组
            in.nextToken();
            a[i] = (int) in.nval;
        }

        for (int i = 0; i < n; i++) {//单调栈模板(注意是数值)
            while (!stack.isEmpty() && stack.peekFirst() >= a[i]) stack.poll();
            if (!stack.isEmpty()) ans[i] = stack.peekFirst();
            else ans[i] = -1;
            stack.push(a[i]);
        }

        for (int i = 0; i < n; i++) {//输出结果
            System.out.print(ans[i] + " ");
        }
    }
}

下面,我们再来看看其他几种情况,基本上都是大同小异。

2. 寻找左边第一个小于它的数的下标

public class Main {
    static int N = (int) (1e5 + 10);
    static int[] a = new int[N], ans = new int[N];
    static Deque<Integer> stack = new LinkedList<>();
    static StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));

    public static void main(String[] args) throws IOException {
        in.nextToken();
        int n = (int) in.nval;
        for (int i = 0; i < n; i++) {//存数组
            in.nextToken();
            a[i] = (int) in.nval;
        }

        for (int i = 0; i < n; i++) {//单调栈模板(注意是下标)
            while (!stack.isEmpty() && a[stack.peekFirst()] >= a[i]) stack.poll();//注意这里的第二个条件是a[stack.peekFirst()] 而不是stack.peekFirst()
            if (!stack.isEmpty()) ans[i] = stack.peekFirst();
            else ans[i] = -1;
            stack.push(i);//这里也不再是a[i],而是存储对应的下标
        }

        for (int i = 0; i < n; i++) {//输出结果
            System.out.print(ans[i] + " ");
        }
    }
}

3. 寻找右边第一个大于它的数

题目描述: 给定一个长度为 n ≤ 10 ^5 的数组 a,输出每个数右边第一个比它大的数,如果不存在

则输出 − 1。之前我们是在一个数的左边去寻找,所以让栈去保存这个数左边的所有数,类似地,

现在需要让栈去保存这个数右边的所有数考虑将数组翻转(倒序遍历),因此情形三变成了「寻找

一个数左边第一个大于它的数」,属于情形一

Java代码如下:

public class Main {
    static int N = (int) (1e5 + 10);
    static int[] a = new int[N], ans = new int[N];
    static Deque<Integer> stack = new LinkedList<>();
    static StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));

    public static void main(String[] args) throws IOException {
        in.nextToken();
        int n = (int) in.nval;
        for (int i = 0; i < n; i++) {//存数组
            in.nextToken();
            a[i] = (int) in.nval;
        }

        for (int i = n - 1; i >= 0; i--) {//单调栈模板(注意是数值)
            while (!stack.isEmpty() && stack.peekFirst() <= a[i]) stack.poll();
            if (!stack.isEmpty()) ans[i] = stack.peekFirst();
            else ans[i] = -1;
            stack.push(a[i]);
        }

        for (int i = 0; i < n; i++) {//输出结果
            System.out.print(ans[i] + " ");
        }
    }
}

4. 寻找右边第一个大于它的数的下标

题目描述: 给定一个长度为 n ≤ 10 ^5 的数组 a,输出每个数右边第一个比它大的数的下标,如果

不存在则输出− 1。结合情形二和情形三即可写出代码。

Java代码如下:

public class Main {
    static int N = (int) (1e5 + 10);
    static int[] a = new int[N], ans = new int[N];
    static Deque<Integer> stack = new LinkedList<>();
    static StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));

    public static void main(String[] args) throws IOException {
        in.nextToken();
        int n = (int) in.nval;
        for (int i = 0; i < n; i++) {//存数组
            in.nextToken();
            a[i] = (int) in.nval;
        }

        for (int i = n-1; i >= 0; i--) {//单调栈模板(注意是下标)
            while (!stack.isEmpty() && a[stack.peekFirst()] <= a[i]) stack.poll();
            if (!stack.isEmpty()) ans[i] = stack.peekFirst();
            else ans[i] = -1;
            stack.push(i);
        }

        for (int i = 0; i < n; i++) {//输出结果
            System.out.print(ans[i] + " ");
        }
    }
}

总结以上情形:

  • 遍历顺序(以怎样的顺序遍历数组 a );
  • 比较方式(如何比较当前元素和栈顶元素);
  • 栈中存储的是什么(是元素本身还是元素的

七、知识小结

初学一门技术时,总有些许的疑惑,别怕,它们是我们学习路上的点点繁星,帮助我们不断成长。

文章粗浅,希望对大家有帮助!

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

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

相关文章

春晚魔术中的数学知识

蛇年春晚刘谦魔术又和大家普及了一下编程中的冒泡排序法&#xff0c;思考深入一点&#xff0c;它还涉及到群论和组合数学中的一些知识。 游戏规则和操作步骤&#xff0c;任意打乱三种餐具作为初始状态&#xff1a; 1.筷子和左边的东西互换&#xff0c;如果筷子就在左边&#…

OpenCV:开运算

目录 1. 简述 2. 用腐蚀和膨胀实现开运算 2.1 代码示例 2.2 运行结果 3. 开运算接口 3.1 参数详解 3.2 代码示例 3.3 运行结果 4. 开运算应用场景 5. 注意事项 6. 总结 相关阅读 OpenCV&#xff1a;图像的腐蚀与膨胀-CSDN博客 OpenCV&#xff1a;闭运算-CSDN博客 …

基于Springboot的健身房管理系统【附源码】

基于Springboot的健身房管理系统 效果如下&#xff1a; 系统登陆页面 管理员主页面 器材类型管理页面 健身房管理页面 教练管理页面 用户管理页面 个人信息页面 课程管理页面 研究背景 随着健康意识的不断增强和人们生活水平的提高&#xff0c;健身房已经成为了现代城市中不…

扣子平台音频功能:让声音也能“智能”起来。扣子免费系列教程(14)

在数字化时代&#xff0c;音频内容的重要性不言而喻。无论是在线课程、有声读物&#xff0c;还是各种多媒体应用&#xff0c;音频都是传递信息、增强体验的关键元素。扣子平台的音频功能&#xff0c;为开发者和内容创作者提供了一个强大而灵活的工具&#xff0c;让音频的使用和…

初始Python篇(8)—— 异常

找往期文章包括但不限于本期文章中不懂的知识点&#xff1a; 个人主页&#xff1a;我要学编程(ಥ_ಥ)-CSDN博客 所属专栏&#xff1a; Python 目录 异常介绍 异常的处理 try-except try-except-else try-except-else-finally 异常的抛出 常见的异常类型 异常介绍 在…

SSM-MyBatis-总结

文章目录 一、Hello MyBatis1.1 流程1.2 总结 二、Crud 的一些注意点三、参数传递3.1 #{ } VS ${ }3.2 单、复参数传递&#xff08;1&#xff09;单参数&#xff08;2&#xff09;多参数 -- Param&#xff08;3&#xff09;总结 四、查询结果返回--结果封装4.1 ResultType 一般…

【算法设计与分析】实验1:字符串匹配问题的算法设计与求解

目录 一、实验目的 二、实验环境 三、实验内容 四、核心代码 五、记录与处理 六、思考与总结 七、完整报告和成果文件提取链接 一、实验目的 给定一个文本&#xff0c;在该文本中查找并定位任意给定字符串。 1、深刻理解并掌握蛮力法的设计思想&#xff1b; 2、提高应用…

10.6.1 文本文件读、写和追加

版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请在显著位置标明本文出处以及作者网名&#xff0c;未经作者允许不得用于商业目的。 文本文件的读写通常的做法是建立一个与文件关联的filestream&#xff0c;然后使用StreamReader读取或者StreamWriter写入。 为了详…

DevEco Studio 4.1中如何创建OpenHarmony的Native C++ (NAPI)程序

目录 引言 操作步骤 结语 引言 OpenHarmony的开发工具变化很快&#xff0c;有的时候你安装以前的教程进行操作时会发现界面和操作方式都变了&#xff0c;进行不下去了。比如要在OpenHarmony中通过NAPI调用C程序&#xff0c;很多博文&#xff08;如NAPI篇【1】——如何创建含…

达梦拷贝DM_HOME的复制安装

近期一个项目需求&#xff0c;需要在没有安装包的情况下&#xff0c;将达梦数据库安装到虚机上&#xff08;生产机上安装了达梦&#xff09;&#xff0c;故采用直接打包生产机DM_HOME的方式拷贝至虚机&#xff0c;再依次执行达梦的部分指令完成安装。以下为验证的步骤&#xff…

【MySQL】初始MySQL、库与表的操作

目录 基本使用 使用案例 SQL分类 存储引擎 库的操作 字符集和校验规则 查看系统默认字符集和校验规则 查看数据库支持的字符集 查看数据库支持的字符集校验规则 指定编码常见数据库 校验规则对数据库的影响 操纵数据库 库的备份与恢复 表的操作 创建表 查看表 …

AI大模型开发原理篇-2:语言模型雏形之词袋模型

基本概念 词袋模型&#xff08;Bag of Words&#xff0c;简称 BOW&#xff09;是自然语言处理和信息检索等领域中一种简单而常用的文本表示方法&#xff0c;它将文本看作是一组单词的集合&#xff0c;并忽略文本中的语法、词序等信息&#xff0c;仅关注每个词的出现频率。 文本…

“爱”之浅谈(一)

《九重紫》里 陈嘉有了爱情 从粗糙的一介武夫和赌徒&#xff0c;变得温柔细致 万皇后伤于爱情 从温柔的眼里有爱有光的小姑娘&#xff0c;变成狠毒的残害忠良的、意图谋反的、卷动举国风云的操盘手 “爱让怯懦者勇敢&#xff0c;让高傲者低头” “爱是软肋&#xff0c;也是…

图漾相机搭配VisionPro使用简易教程

文章目录 1.下载并安装VisionPro软件2.下载PercipioCameraForVisionPro软件包3.软件部署4.测试流程4.1 遍历VisionPro SDK支持的参数4.2 设置示例4.2.1_cameraSingle.SetTriggerMode4.2.2 _cameraSingle.SetRegistration4.2.3_cameraSingle.SetInt4.2.4 _cameraSingle.GetInt4.…

Versal - 基础3(AXI NoC 专题+仿真+QoS)

目录 1. 简介 2. 示例 2.1 示例说明 2.2 创建项目 2.2.1 平台信息 2.2.2 AXI NoC Automation 2.2.3 创建时钟和复位 2.3 配置 NoC 2.4 配置 AXI Traffic 2.5 配置 Memory Size 2.6 Validate BD 2.7 添加观察信号 2.8 运行仿真 2.9 查看结果 2.9.1 整体波形 2.9…

iperf 测 TCP 和 UDP 网络吞吐量

注&#xff1a;本文为 “iperf 测网络吞吐量” 相关文章合辑。 未整理去重。 使用 iperf3 监测网络吞吐量 Tom 王 2019-12-21 22:23:52 一 iperf3 介绍 (1.1) iperf3 是一个网络带宽测试工具&#xff0c;iperf3 可以擦拭 TCP 和 UDP 带宽质量。iperf3 可以测量最大 TCP 带宽…

ResNeSt: Split-Attention Networks论文学习笔记

这张图展示了一个名为“Split-Attention”的神经网络结构&#xff0c;该结构在一个基数组&#xff08;cardinal group&#xff09;内进行操作。基数组通常指的是在神经网络中处理的一组特征或通道。图中展示了如何通过一系列操作来实现对输入特征的注意力机制。 以下是图中各部…

自动驾驶---苏箐对智驾产品的思考

1 前言 对于更高级别的自动驾驶&#xff0c;很多人都有不同的思考&#xff0c;方案也好&#xff0c;产品也罢。最近在圈内一位知名的自动驾驶专家苏箐发表了他自己对于自动驾驶未来的思考。 苏箐是地平线的副总裁兼首席架构师&#xff0c;同时也是高阶智能驾驶解决方案SuperDri…

【C++】内联函数inline、关键字auto与新式for

内联函数 内联函数背景 我们在使用C语言中我们都学过函数&#xff0c;我们知道函数在调用的过程中需要开辟栈帧。如果我们需要频繁的调用一个函数&#xff0c;假设我们调用10次Add()函数&#xff0c;那我们就需要建立10次栈帧。我们都知道在栈帧中要做很多事情&#xff0c;例如…

Day24-【13003】短文,数据结构与算法开篇,什么是数据元素?数据结构有哪些类型?什么是抽象类型?

文章目录 13003数据结构与算法全书框架考试题型的分值分布如何&#xff1f; 本次内容概述绪论第一节概览什么是数据、数据元素&#xff0c;数据项&#xff0c;数据项的值&#xff1f;什么是数据结构&#xff1f;分哪两种集合形式&#xff08;逻辑和存储&#xff09;&#xff1f…