算法学习Day1——【数据结构】单调栈

1.什么是单调栈以及单调栈的作用

(1)定义

顾名思义,单调栈是一个有序的栈,可能从栈顶到栈底单调递增(单调递增栈),也有可能从栈顶到栈底单调递减(单调递减栈)。

(2)用途

单调栈可以在时间复杂度为 O(n)$的情况下,求解出某个元素左边或者右边第一个比它大或者小的元素。

所以单调栈一般用于解决一下几种问题:

1.寻找左侧第一个比当前元素大的元素。

2.寻找左侧第一个比当前元素小的元素。

3.寻找右侧第一个比当前元素大的元素。

4.寻找右侧第一个比当前元素小的元素。

那么我们在这里进行对上述四种问题进行阐述,

1.寻找左侧第一个比当前元素大的元素,我们可以创建一个单调递增栈,把我们这个元素与栈顶元素进行比较,如果栈顶元素小于要该元素,那么直接将栈顶元素弹出,然后继续比较,直到找到第一个比这个元素大的元素,或者说栈为空,如果栈为空,那么说明左边不存在比这个元素更大的元素了

2.寻找左侧第一个比当前元素小的元素,我们创建一个单调递减栈,将这个栈顶元素和该元素进行比较,如果该项元素大于栈顶元素,那么就要将该元素插入,并且此时的栈顶元素就是左侧第一个比该元素小的元素

3.寻找右侧第一个比当前元素大的元素,我们创建一个单调递增栈,然后从左向右遍历,第一个将这个元素从栈中弹出的元素就是右侧第一个比这个元素大的

4.寻找右侧第一个比当前元素小的元素,我们要创建单调递减栈,然后从左向右遍历,就是第一个将该元素从栈中弹出的就是右侧第一个比这个元素小的

(3)伪代码

cpp 复制代码
stack<int> st;
//此处一般需要给数组最后添加结束标志符,具体下面例题会有详细讲解
for (遍历这个数组)
{
	if (栈空 || 栈顶元素大于等于当前比较元素)
	{
		入栈;
	}
	else
	{
		while (栈不为空 && 栈顶元素小于当前元素)
		{
			栈顶元素出栈;
			更新结果;
		}
		当前数据入栈;
	}
}

2.相关例题

1.模版单调栈

纯模版题,没啥可说的,记得往栈里面存的是结构体就行

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
int n;

int f[3000005];
struct node
{
	int w;
	int flag;
}a[3000005];
stack<node> q;
int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i].w;
		a[i].flag=i;
	}
	for(int i=1;i<=n;i++)
	{
		while(!q.empty()&&a[q.top().flag].w<a[i].w)
		{
			f[q.top().flag]=i;
			q.pop();
		}
		q.push(a[i]);
    }
	for(int i=1;i<=n;i++)
	{
		printf("%d ",f[i]);
	}
}

2.Look Up S

和上面的题一个板子

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
int n;
struct node{
	int h;
	int flag;
}a[100005];
int f[100005];
stack<node> q;
int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i].h;
		a[i].flag=i;
	}
	for(int i=1;i<=n;i++)
	{
		while(!q.empty()&&q.top().h<a[i].h)
		{
			f[q.top().flag]=i;
			q.pop();
		}
		q.push(a[i]);
	}
	for(int i=1;i<=n;i++)
	{
		printf("%d\n",f[i]);
	}
}

3. 求数列所有后缀最大值的位置

这题两个知识点,一个是异或操作,另一个是单调栈

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;

struct node{
	unsigned long long w;
	int flag;
}a[1000005];
int n;
long long sum;
stack<node> q;
int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
    {
     	cin>>a[i].w;
     	a[i].flag=i;
	}
	for(int i=1;i<=n;i++)
	{
		while(!q.empty()&&q.top().w<a[i].w)
		{
			sum^=q.top().flag;
			q.pop();
		}
		q.push(a[i]);
		sum^=q.top().flag;
		printf("%lld\n",sum);
	}
	return 0;
} 
相关推荐
别NULL1 分钟前
机试题——疯长的草
数据结构·c++·算法
TT哇5 分钟前
*【每日一题 提高题】[蓝桥杯 2022 国 A] 选素数
java·算法·蓝桥杯
小A15922 分钟前
STM32完全学习——SPI接口的FLASH(DMA模式)
stm32·嵌入式硬件·学习
火烧屁屁啦28 分钟前
【JavaEE进阶】初始Spring Web MVC
java·spring·java-ee
w_312345442 分钟前
自定义一个maven骨架 | 最佳实践
java·maven·intellij-idea
岁岁岁平安44 分钟前
spring学习(spring-DI(字符串或对象引用注入、集合注入)(XML配置))
java·学习·spring·依赖注入·集合注入·基本数据类型注入·引用数据类型注入
武昌库里写JAVA1 小时前
Java成长之路(一)--SpringBoot基础学习--SpringBoot代码测试
java·开发语言·spring boot·学习·课程设计
qq_589568101 小时前
数据可视化echarts学习笔记
学习·信息可视化·echarts
Q_19284999061 小时前
基于Spring Boot的九州美食城商户一体化系统
java·spring boot·后端
张国荣家的弟弟1 小时前
【Yonghong 企业日常问题 06】上传的文件不在白名单,修改allow.jar.digest属性添加允许上传的文件SH256值?
java·jar·bi