1.自然语言描述
①单链表:这里使用的是不带头结点的单链表,由一个指向第一个结点的head指针,e数组(e[i]表示第i个插入列表的结点)ne数组(ne[i]表示第i个插入链表的结点的邻接结点)idx表示下一次插入结点的序号。
②双链表:在单链表的基础上加入了每个结点左邻接的结点数组。
③栈:先进后出表,用数组模拟,tt表示栈顶。
④队列:先进先出表,用数组模拟,hh表示队首,tt表示队尾。
⑤单调栈:不断pop栈输出直到栈空,如果得到单调递增序列则为单调递增栈,反之为单调递减栈。对于一个序列,为了找出序列中每一个元素左边第一个比它小的元素,可以用单调递减栈作为数据结构。
⑥单调队列:和单调栈类似,最典型的应用是滑动窗口问题。
2.代码
Acwing 830. 单调栈
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN=1e5+10;
int skt[MAXN],tt;
int main(void)
{
int n;
cin>>n;
for(int i=0;i<n;i++){
int x;
cin>>x;
//每插入一个数,判断栈顶元素是否大于等于它,如果成立,则出栈。
//这使得栈顶始终是之前出现过的第一个小于当前数的元素。
while(tt&&skt[tt]>=x) tt--;
if(tt) cout<<skt[tt]<<' ';
else cout<<"-1"<<' ';
skt[++tt]=x;
}
cout<<endl;
for(int i=1;i<=tt;i++)
cout<<skt[i]<<' ';
return 0;
}
Acwing 154.滑动窗口
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN=1e6+10;
int q[MAXN],a[MAXN];
int n,k;
int main(void)
{
scanf("%d%d",&n,&k);
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
//find the minnum
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]]);
}
printf("\n");
//fint the maxnum
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]]);
}
return 0;
}