算法总结——单调栈

news2024/11/19 5:49:49

在这里插入图片描述
纵有疾风起,人生不言弃。本文篇幅较长,如有错误请不吝赐教,感谢支持。

文章目录

    • 一、单调栈的定义
    • 二、单调栈的应用:
      • 寻找左边第一个比它小的数
      • 寻找左边第一个比它小的数的下标
      • 寻找右边第一个小于它的数
      • 寻找右边第一个小于它的数的下标
      • 单调栈总结

一、单调栈的定义

单调栈不是一种新的数据结构,它在结构上仍然是一个普通栈,只是在使用方法上有所区别。单调栈内的元素是单调递增或递减的,因此有单调递增栈和单调递减栈。

  • 单调递增栈: 栈中元素从栈底到栈顶是递增的。
  • 单调递减栈: 栈中元素从栈底到栈顶是递减的。

我们在使用单调栈的时候,要时刻保证栈的单调性,例如,单调递增栈:栈中元素从栈底到栈顶是递增的。当一个元素入栈时,与栈顶比较,若比栈顶大,则入栈;若比栈项小,则弹出栈顶,直到这个数能入栈为止。注意:每个元素都一定入栈
单调栈的核心思想就是:

及时去掉无用数据,保证栈中数据有序

二、单调栈的应用:

单调栈的应用:用来在一个数组中寻找某一个元素左边(或右边)第一个大于(或小于或大于等于或小于等于)它的元素(或元素的下标)。

寻找左边第一个比它小的数

题目练习: AcWing 830. 单调栈
给定一个长度为 N 的整数数列,输出每个数左边第一个比它小的数,如果不存在则输出 −1。
输入格式
第一行包含整数 N,表示数列长度。
第二行包含 N 个整数,表示整数数列。
输出格式
共一行,包含 N 个整数,其中第 i 个数表示第 i 个数的左边第一个比它小的数,如果不存在则输出 −1。
数据范围
1≤N≤10 5 {5} 5
1≤数列中元素≤ 1 0 9 10^{9} 109
输入样例:

5
3 4 2 7 5

输出样例:

-1 3 -1 2 2

思路:传统的暴力做法是双重循环,两个指针i和j,i用来遍历序列,j用来扫描i左边的所有数。时间复杂度是O( n 2 n^{2} n2)

#include<iostream>

using namespace std;

const int Max = 1e5 + 10;

int n,arr[Max];

int main() {
    cin >> n;
    for (int i = 0; i < n; i++) cin >> arr[i];

    for (int i = 0; i < n; i++) {
        bool flag = false;//标志 
        for (int j = i - 1; j>=0; j--) {
            if (arr[j] < arr[i]) {
                flag = true;
                cout << arr[j] << ' ';
                break;
            }
        }
        if (!flag) cout << -1 << ' ';
		//如果flag为false,说明左边没有比该元素小的 
    } 
    return 0;
}

我们要是使用单调栈可以将时间复杂度优化到O(n)。
单调栈的思想( 及时去掉无用数据,保证栈中数据有序):
在指针 i 从左往右遍历的过程中,我们可以用一个栈来保存 i左边的所有元素(不包括i指向的元素),下标越大的元素越接近栈顶,下标越小的元素越接近栈底,然后从栈顶开始找符合条件的(小于该元素),把栈内不符合条件的无用数据全部出栈(大于等于该元素),无用数据之后再也用不到了,最后的栈顶就是答案。
我们来举一个例子:
2 4 5 3 1假如此时3入栈;3左边的4、5都没有存在的必要了(因为3比4和5更小,并且更靠近下一个即将入栈的元素),4、5出栈,然后2比3小,停下符合条件,最后的栈顶2就是答案。
代码:

#include<iostream>
#include<stack>
using namespace std;
const int Max=1e5+10;
int n,arr[Max],ans[Max];
stack<int> stk;
int main()
{
	cin>>n;
	for(int i=0;i<n;i++) cin>>arr[i];//arr完整数组
	for(int i=0;i<n;i++)
	{
		while(!stk.empty()&&stk.top()>=arr[i]) stk.pop();//把栈内不符合条件的无用数据全部出栈(大于等于该元素),
		if(!stk.empty()) ans[i]=stk.top();//最后的栈顶就是答案。
		else ans[i]=-1;
		stk.push(arr[i]);
	}
	for(int i=0;i<n;i++) cout<<ans[i]<<' ';
	return 0;
}

注:arr数组和ans数组可以不创建,但为了方便统一单调栈的格式,所以创建。

寻找左边第一个比它小的数的下标

与上面的差不多,注意到之前我们寻找的是元素所以让栈去保存元素,现在我们寻找下标,所以让栈去保存元素的下标就可以了

#include<iostream>
#include<stack>
using namespace std;
const int Max=1e5+10;
int n,arr[Max],ans[Max];
stack<int> stk;
int main()
{
	cin>>n;
	for(int i=0;i<n;i++) cin>>arr[i];//arr完整数组
	for(int i=0;i<n;i++)
	{
		while(!stk.empty()&&arr[stk.top()]>=arr[i]) stk.pop();//把栈内不符合条件的无用数据全部出栈(大于等于该元素),
		if(!stk.empty()) ans[i]=stk.top();//最后的栈顶就是答案。
		else ans[i]=-1;
		stk.push(i);
	}
	for(int i=0;i<n;i++) cout<<ans[i]<<' ';
	return 0;
}

寻找右边第一个小于它的数

寻找右边,我们可以换一种思想,将数组翻转,转换为寻找左边第一个小于自己的数 ,实际上不可能翻转,而是倒序遍历,因此变成了寻找一个数左边第一个小于它的数,于是归结为情形一。

#include<iostream>
#include<stack>
using namespace std;
const int Max=1e5+10;
int n,arr[Max],ans[Max];
stack<int> stk;
int main()
{
	cin>>n;
	for(int i=0;i<n;i++) cin>>arr[i];//arr完整数组
	for(int i=n-1;i>=0;i--)
	{
		while(!stk.empty()&&stk.top()>=arr[i]) stk.pop();//把栈内不符合条件的无用数据全部出栈(大于等于该元素),
		if(!stk.empty()) ans[i]=stk.top();//最后的栈顶就是答案。
		else ans[i]=-1;
		stk.push(arr[i]);
	}
	for(int i=0;i<n;i++) cout<<ans[i]<<' ';
	return 0;
}

寻找右边第一个小于它的数的下标

P5788 【模板】单调栈
题目描述

给出项数为 n n n 的整数数列 a 1 … n a_{1 \dots n} a1n

定义函数 f ( i ) f(i) f(i) 代表数列中第 i i i 个元素之后第一个大于 a i a_i ai 的元素的下标,即 f ( i ) = min ⁡ i < j ≤ n , a j > a i { j } f(i)=\min_{i<j\leq n, a_j > a_i} \{j\} f(i)=mini<jn,aj>ai{j}。若不存在,则 f ( i ) = 0 f(i)=0 f(i)=0

试求出 f ( 1 … n ) f(1\dots n) f(1n)

输入格式

第一行一个正整数 n n n

第二行 n n n 个正整数 a 1 … n a_{1\dots n} a1n

输出格式

一行 n n n 个整数表示 f ( 1 ) , f ( 2 ) , … , f ( n ) f(1), f(2), \dots, f(n) f(1),f(2),,f(n) 的值。

样例 #1
样例输入 #1

5
1 4 2 3 5

样例输出 #1

2 5 4 5 0

【数据规模与约定】
对于 30 % 30\% 30% 的数据, n ≤ 100 n\leq 100 n100

对于 60 % 60\% 60% 的数据, n ≤ 5 × 1 0 3 n\leq 5 \times 10^3 n5×103

对于 100 % 100\% 100% 的数据, 1 ≤ n ≤ 3 × 1 0 6 1 \le n\leq 3\times 10^6 1n3×106 1 ≤ a i ≤ 1 0 9 1\leq a_i\leq 10^9 1ai109
AC代码

#include<iostream>
#include<stack>
using namespace std;
const int Max = 3e6 + 10;

int n,arr[Max], ans[Max];
stack<int> stk;

int main() 
{
    cin >> n;
    for (int i = 1; i <= n; i++) cin >> arr[i];

    for (int i = n; i>=1; i--)
    {
        while (!stk.empty() && arr[stk.top()] <= arr[i]) stk.pop();
        if (!stk.empty()) ans[i] = stk.top();
        else ans[i]=0;//可不写,ans数组默认初始化全为0
        stk.push(i);
    }

    for (int i = 1; i <= n; i++) cout << ans[i] << ' ';

    return 0;
}

单调栈总结

①遍历顺序,找某个数的左边就正序遍历,右边就倒序遍历
②及时去掉无用数据的方式,如果找小于该元素,那就出栈中所有大于等于该元素的元素,此时的栈顶就是答案(栈不为空的情况下)。
③栈中存的是元素还是元素下标。

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

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

相关文章

HCIP -- 重发布实验

要求&#xff1a; 实现&#xff1a; [rl]interface LoopBack 0 [rl-LoopBack0]ip ad [rl-LoopBack0]ip address 1.1.1.1 32 [rl-LoopBack0]q [rl]int [rl]interface go/0/0 [rl-GigabitEthernet0/0/0]ip add [rl-GigabitEthernet0/0/0]ip address 12.1.1.1 24on the interface…

第二篇:新建node项目并运行

&#x1f3ac; 江城开朗的豌豆&#xff1a;个人主页 &#x1f525; 个人专栏 :《 VUE 》 《 javaScript 》 &#x1f4dd; 个人网站 :《 江城开朗的豌豆&#x1fadb; 》 ⛺️ 生活的理想&#xff0c;就是为了理想的生活 ! 安装 Node.js&#xff1a;首先&#xff0c;确保你的…

一篇文章带你了解接口测试(总结)

接口测试是软件测试中的一块重要部分&#xff0c;简言之&#xff0c;接口测试是指验证软件系统中各个模块间接口处的交互是否正确。 接口是软件组件之间交互的协议&#xff0c;允许不同的软件系统或模块通过明确定义的方法通信和交换数据。 一. 接口测试的重要性 在微服务架…

Agent检索增强生成

检索增强生成(RAG)设计模式通常用于在特定数据域中开发大语言模型(LLM)应用。然而&#xff0c;RAG的过往的研究重点主要在于提高检索工具的效率&#xff0c;例如嵌入搜索、混合搜索和微调嵌入&#xff0c;而忽视了智能搜索。本文介绍了一种受人类研究方法启发的新方法&#xff…

WordPress企业模板

首页大图wordpress外贸企业模板 橙色的wordpress企业模板 演示 https://www.zhanyes.com/waimao/6250.html

PDF有编辑密码怎么办

目录 注意&#xff1a; windows方法&#xff1a; 1 python 下载 2 打开命令行 3 安装 pikepdf 4 编写python脚本 5 使用py脚本 6解密完成 Linux方法&#xff1a; 注意&#xff1a; 此方法可以用于破解PDF的编辑密码&#xff0c;而不是PDF的打开密码 当遇到类似如下问…

SSC | Blue Prism报告:2024年智能自动化(IA)7大趋势预测

近日&#xff0c;RPA行业领导者SS&C | Blue Prism发布《2024智能自动化&#xff08;IA&#xff09;趋势与预测》报告。报告中提到&#xff0c;智能自动化&#xff08;IA&#xff09;与流程管理的有效融合&#xff0c;是实现数字化转型成功的核心。采用业务流程管理&#xf…

工业物联网的关键技术——青创智通工业物联网

1. 传感器技术&#xff1a;传感器是实现工业物联网感知层的重要技术之一&#xff0c;能够将物理量、化学量、生物量转化为可处理的数字信号&#xff0c;从而实现对物体状态的实时监测和自动控制。传感器技术是工业物联网应用中的关键核心技术之一&#xff0c;其性能和精度直接影…

Linux--部署 Tomcat 及其负载均衡

1.案例前置知识点 1&#xff09;Tomcat简介 名称由来&#xff1a;Tomcat最初是由 Sun的软件构架师詹姆斯邓肯戴维森开发的。后来他帮助将其变 为开源项目&#xff0c;并由Sun贡献给Apache软件基金会。由于大部分开源项目OReilly都会出一本相关的 书&#xff0c;并且将其封面设…

走迷宫之推箱子

前言&#xff1a; 在上一篇文章当中我介绍了一个走迷宫的写法&#xff0c;但是那个迷宫没什么可玩性和趣味性&#xff0c;所以我打算在迷宫的基础上加上一个推箱子&#xff0c;使之有更好的操作空间&#xff0c;从而增强了游戏的可玩性和趣味性。 1. 打印菜单 void menu() {…

python绘制热力图-数据处理-VOC数据类别标签分布及数量统计(-代码)

Python是一种功能强大的编程语言&#xff0c;它提供了许多库和工具&#xff0c;用于处理和可视化数据。在本文中&#xff0c;我们将介绍使用Python绘制热力图&#xff0c;并对VOC数据集中的类别标签进行分布及数量统计。 首先&#xff0c;我们需要导入所需的库。使用numpy库来…

【Java】后端开发语言Java和C#,两者对比注解和属性的区别以及作用

欢迎来到《小5讲堂》 大家好&#xff0c;我是全栈小5。 这是《Java》序列文章&#xff0c;每篇文章将以博主理解的角度展开讲解&#xff0c; 特别是针对知识点的概念进行叙说&#xff0c;大部分文章将会对这些概念进行实际例子验证&#xff0c;以此达到加深对知识点的理解和掌握…

SpringBoot 源码解析4:refresh 方法解析

SpringBoot 源码解析4&#xff1a;refresh 方法解析 1. refresh 方法解析2. 准备刷新 AbstractApplicationContext#prepareRefresh3. 获取bean工厂 AbstractApplicationContext#obtainFreshBeanFactory4. 准备bean工厂 AbstractApplicationContext#prepareBeanFactory5. Servle…

Windows解决.conda文件夹占用C盘空间过大的问题

背景&#xff1a;C盘空间被.conda文件占用16G&#xff0c;主要原因是里面存放了python环境&#xff0c;提前进行环境迁移&#xff0c;防止后面环境增长C盘空间不足 解决办法&#xff1a; 1. .conda文件备份 2. 将.conda文件夹中的envs内容复制到Anaconda的安装目录下D:\Softwa…

HNU-编译原理-实验2-Bison

编译原理实验2Bison 计科210X 甘晴void 202108010XXX 实验要求 详细的实验项目文档为 https://gitee.com/coderwym/cminus_compiler-2023-fall/tree/master/Documentations/lab2 实验步骤 本次实验需要在 Lab1 已完成的 flex 词法分析器的基础上&#xff0c;进一步使用 b…

车机联网

通过笔记本电脑&#xff0c;D-link给车机提供网络 因为笔记本用的无线网络上网&#xff0c;将无线网络连接设置为共享 设置后的效果 本地连接属性设置 Dlink连接电脑和车机&#xff1b;获取车机的动态ip&#xff08;动态ip每次开关机都会变化&#xff0c;注意更新&#xff09…

【python 的各种模块】(9) 在python使用PIL( 即pillow模块 ) 修改图片

目录 1 导入PIL模块&#xff08;pillow&#xff09; 1.1 PIL的全称&#xff1a;Python Imaging Library 1.2 导入PIL模块 1.2.1 可用的导入形式 1.2.2 常用的导入形式 1.2.3 PIL下面的常用子模块 2 PIL.Image的方法 (读入&#xff0c;生成和显示图片) 2.1 用 PIL.Image…

《教育》期刊是什么级别的期刊?是正规期刊吗?能评职称吗?

《教育》以教育行业的各类新闻为重点&#xff0c;积极推广各地教育部门改革经验及优秀成果&#xff0c;努力挖掘教育一线先进单位和个人&#xff0c;充分发挥新闻舆论的监督作用。 收录情况&#xff1a;知网收录 投稿方式&#xff1a;教育类&#xff5c;《教育》省级 出版周期&…

GPT2 GPT3

what is prompt 综述1.Pre-train, Prompt, and Predict: A Systematic Survey of Prompting Methods in Natural Language Processing(五星好评) 综述2. Paradigm Shift in Natural Language Processing(四星推荐) 综述3. Pre-Trained Models: Past, Present and Future Pro…

Vue学习笔记5-- nextTick | Vue封装的过渡与动画

一、nextTick(tick-工作&#xff0c;起作用&#xff1b;下次起作用&#xff09; 语法&#xff1a; this.$nextTick(回调函数&#xff09;作用&#xff1a;在下一次DOM更新结束后执行其指定的回调。什么时候用&#xff1a;当改变数据后&#xff0c;要基于更新后的新DOM进行某些…