数组模拟队列&栈

数组模拟队列&栈

#include<iostream>

using namespace std;

const int N=100010;

int stk[N],tt;//栈一般定义为stk[N],tt为栈点下标,栈习惯上从0开始
//插入 
skt[++tt]=x;//表示在栈顶加入一个新的元素 
//弹出
tt--;
//判断栈是否为空
if(tt>0)//说明不空
else //empty 
//栈顶元素
stk[tt]; 

队列

//模拟队列
int q[N],hh,tt=-1;//队列习惯上从-1开始
//插入
q[++tt]=x;
//弹出
hh++;//将队头的指针向后移动一位则为弹出
//判断是否为空
if(hh<=tt) not empty
else empty
//取出队头元素
q[hh];
//还可以取出队尾
q[tt]; 

单调栈

题目:

输入一串数字,找到每一个数字所对应的在他左边离他最近且比他小的数,如果有这个数,则输出,若无,则输出-1

#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 x;
		cin>>x;
		while(tt&&stk[tt]>=x) tt--;//当栈非空并且栈顶元素大于此时读入的这个x,那么这个栈顶元素就再也不会被用到了,因为要让序列为单调递增 
		if(tt) cout<<stk[tt]<<' ';//若栈非空,则说明该栈顶元素为离他最近的一个小于它的元素
		else	cout<<-1<<' ';//否则说明找不到这样的数,则返回-1
		
		stk[++tt]=x;//最后要记得把该数再插回到队列当中
	}
	return 0;
}

单调队列

题目:

给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。

返回滑动窗口中的最小值和最大值。

示例 1:

输入:nums = [1,3,-1,-3,5,3,6,7], k = 3
输出:	[-1,-3,-3,-3,3,3]
	  [3,3,5,5,6,7]
解释:
滑动窗口的位置                最大值

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

[1  3  -1] -3  5  3  6  7       3
 1 [3  -1  -3] 5  3  6  7       3
 1  3 [-1  -3  5] 3  6  7       5
 1  3  -1 [-3  5  3] 6  7       5
 1  3  -1  -3 [5  3  6] 7       6
 1  3  -1  -3  5 [3  6  7]      7

思路:

用一个队列来存,当窗口在滑动时,将即将要滑到的元素插入到队尾,将即将要划走的元素从队头弹出来。

在找到最值时,若用遍历枚举的话,会造成时间复杂度高,则此处和单调栈相同思路,先用暴力做法,再看在栈和队列中有哪些元素是没有用到的,将这些元素删掉后,再去看剩下的元素是否具有单调性,即可优化:

若取极值则取端点,若取某个点则用二分法

代码:

#include<iostream>

using namespace std;

const int N=1000010;

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++;
		while(hh<=tt && a[q[tt]]>=a[i])
			tt--;//若队尾的数大于或等于即将进来的数,则将队尾的数出队 
		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;
} 
posted @ 2021-04-12 15:01  小滢小滢考第一名  阅读(62)  评论(0编辑  收藏  举报