用数列实现栈和队列 ,单调栈,单调队列

栈:先进后出

队列:先进先出

一.数列实现栈的各种功能

1.插入  2.弹出  3.判断栈是否为空  4.取栈顶元素

代码实现

int stk[N],tt; //分别代表栈和栈顶的下标 

//插入 
stk[ ++ tt] = x;

//弹出 
tt--;

//判断栈是否为空
if(tt > 0) not empty 
else empty 

//栈顶
stk[tt];

二.数列实现队列的各种功能

1.插入  2.弹出  3.判断队列是否为空  4.取队头元素或队尾元素

//队尾插入元素,在队头弹出元素 
int q[N], hh, tt = -1;

//插入
q[++ tt] = x;

//弹出
hh ++;

//判断队列是否为空
if(hh <= tt) not empty
else empty
 
//取出对头元素
q[hh];
q[tt]; //队尾 
 

三.单调栈

单调栈(monotonous stack)是指栈的内部从栈底到栈顶满足单调性的栈结构

单调栈应用题型十分有限,最常见的题型 :求每一个数左边离他最近且小于他的数(or最大的数)

例题:

第一种做法暴力遍历代码实现:两重循环

优化代码实现:

每个元素最多只会进栈一次,出栈一次,时间复杂度O(n)

#include<iostream>

using namespace std;

const int N = 100010;

int n;
int stk[N], tt;

int main()
{
	cin>>n;
	
	for(int i=0;i<n;i++){
		int m;
		cin>>m;
		while(tt && m <= stk[tt]) tt--;
		if(tt) cout << stk[tt]<<' ';
		else cout<< -1<<' ';
		
		stk[++tt] = m;
	}
	return 0;
} 

思路分析:

一句话概括,就是如果前面的数 比 后面的数 大或相等,那就永远不会用上,从栈内删除即可

详细说明:

第i个数 左边的数可以用栈存起来,如果前面的数大于后面的数,就把前面的数删掉,最后栈里的数变成了严格单调递增

eg:若stk[3]>=stk[5],就把stk[3]删去 ,因为如果stk[3]是我们的目标值,那么换成stk[5]会更好

倘若遍历到第i个数 , i之前的栈内元素已满足严格的单调上升 , 第i个数的值为m,如果stk[tt]>=m , stk[tt]永远都不会被当成答案 , 那么就删掉stk[tt] , tt-- , 直到出现一个比m小的数,最后把m插入到栈顶

应用:每次输入一个数x到栈,如果stk[tt]>=x, 那就把栈顶删掉,当出现stk[tt]<x,那这就是第一个出现的比x小的数,输出stk[tt]

运行时间

建议输出输入使用scanf 和 printf,快了将近10倍 ,也可以加上cin.tie(); 

四.单调队列

经典例题:

 代码实现:

#include<iostream>

using namespace std;

const int N = 100010;

 int n,k;
 int a[N],q[N]; //a数组记录数值,q数组记录下标 
 
 int main(){
 	scanf("%d%d",&n, &k);
 	for(int i=0;i < n; i++) scanf("%d", &a[i]);
 	
 	int hh = 0, tt = -1;
	for(int i = 0; i < n; i ++)
	{
		//判断队列是否已经滑出窗口
		if(hh <= tt && i - k + 1 > q[hh]) hh ++;
        //如果即将入列的值a[i] <= 队列尾部a[q[tt]] , 那么将其移出队列
		while (hh <= tt && a[q[tt]] >= a[i]) tt --;
        //q存入新的索引i ,即将a[i]插入队列
		q[++ tt] = i;
		if(i >= k - 1) printf("%d ",a[q[hh]]);
	 }
	 puts("");
	 
	 hh = 0, tt = -1;
	 for(int i = 0; i < n; i ++)
	{
		//判断队列是否已经滑出窗口
		if(hh <= tt && i - k + 1 > q[hh]) hh ++;
		while (hh <= tt && a[q[tt]] <= a[i]) tt --;
		q[++ tt] = i;
		if(i >= k - 1) printf("%d ",a[q[hh]]);
	 }
	 puts("");
	 
	return 0;
} 

总结

单调栈和单调队列的代码实现,做题步骤都十分相似

如何维护单调性:新元素入栈/队列时,会与栈顶元素/队尾元素进行比较,使得栈/队列始终保持单调性

单调栈和单调队列做题步骤:

1.先考虑用栈和队列暴力模拟这个问题

2.再想想在栈和队列中哪些元素是没有用的,把所有没有用的元素删掉

3.观察剩下的元素是否有单调性,有的话就可以做优化
例如:
取极值 ->可以直接取两个端点
查找一个值->可以用二分

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值