数组模拟栈
//用数组模拟栈
//push x – 向栈顶插入一个数 x
//pop – 从栈顶弹出一个数;
//empty – 判断栈是否为空;
//query – 查询栈顶元素。
#include <iostream>
using namespace std;
const int N = 1e5 + 10;
int a[N], tt;
void init ()
{
tt = -1;//也可以从0开始,后面的单调栈就是从0开始的
}
void push (int x)
{
a[++tt] = x;
}
void pop ()
{
tt -- ;
}
bool empty ()
{
if (tt == -1) return true;
return false;
}
int query ()
{
return a[tt];//注意query的时候不用--
}
int main ()
{
init();
int m;
scanf("%d", &m);
while ( m -- )
{
string op;
int x;
cin >> op;
if(op == "push")
{
cin >> x;
push(x);
}
else if(op == "pop")
{
pop();
}
else if(op == "empty")
{
if(empty()) cout << "YES" << endl;
else cout << "NO" << endl;
}
else cout << query() << endl;
}
return 0;
}
数组模拟队列
//用数组模拟队列
//push x – 向队尾插入一个数 x
//pop – 从队头弹出一个数;
//empty – 判断队列是否为空;
//query – 查询队头元素。
#include <iostream>
using namespace std;
const int N = 1e5 + 10;
int a[N], hh, tt;
void init ()
{
hh = 0;
tt = -1;
}
void push (int x)
{
a[++ tt] = x;
}
void pop ()
{
hh ++ ;
}
bool empty ()
{
if (tt >= hh) return false;
return true;
}
int query ()
{
return a[hh];//注意query的时候不用--
}
int main ()
{
init();
int m;
scanf("%d", &m);
while ( m -- )
{
string op;
int x;
cin >> op;
if(op == "push")
{
cin >> x;
push(x);
}
else if(op == "pop")
{
pop();
}
else if(op == "empty")
{
if(empty()) cout << "YES" << endl;
else cout << "NO" << endl;
}
else cout << query() << endl;
}
return 0;
}
数组模拟单调栈
单调栈要找的是左侧右侧第一个比自己大或者小的数
这里以找到左侧第一个比自己小的数为例
如果a[3]>a[5] ,我们要找a[6]左侧第一个比他小的数字,那么a[3]继续存在栈里就没有意义了,因此把它弹出栈。
单调栈的时间复杂度是O(n)
单调栈有单调递增栈和递减栈
单调递增栈
对于将要入栈的元素来说,在对栈进行更新后(即弹出了所有比自己大的元素),此时栈顶元素就是数组中左侧第一个比自己小的元素;
单调递减栈
对于将要入栈的元素来说,在对栈进行更新后(即弹出了所有比自己小的元素),此时栈顶元素就是数组中左侧第一个比自己大的元素;
什么时候使用单调栈
给定一个序列,求序列中的每一个数左边或右边第一个比他大或比他小的数在什么地方;
BTW:如果是问在什么地方,那么就在栈里面存数在序列中的下标,如果是问数字,那么直接存数字的值即可。
#include <iostream>
using namespace std;
const int N = 1e5 + 10;
int stk[N], tt;
int main()
{
int n;
scanf("%d", &n);
for (int i = 0; i < n; i ++ )
{
int x;
scanf("%d", &x);//这里也可以开辟一个数组在这个for外面重新for一下把序列存起来,但是没必要,因为单调栈只要看当前的栈顶元素即可
//如果这里找的是元素右侧第一个比他大或者比他小的数,那么就需要倒着遍历当前序列,就需要我们先存下来当前序列了
while (tt && stk[tt] >= x) tt -- ;//去除栈中的无效元素,保证栈中元素的单调性,本题维护的是一个单调递增栈
if (tt) cout << stk[tt] << ' ';//栈为空的时候tt = 0,
else cout << -1 << ' ';
stk[ ++ tt] = x;//可以看到第一个元素下标是从1开始的,经过while去除无效元素后(对栈进行更新后),这里直接将元素x放入栈内即可
}
return 0;
}
数组模拟单调队列
单调队列的代码和单调栈的区别
单调队列取出来的时候如果从队头pop那么取出来的是队列中最小的元素,
单调栈从栈顶pop(),取的是离自己最近的一个比自己小的元素;
#include <iostream>
using namespace std;
const int N = 1e6 + 10;
int a[N], q[N], hh, tt = -1;//理论上来说应该是q[k]
int main()
{
int n, k;
scanf("%d%d", &n, &k);
//单调递增队列
for (int i = 0; i < n; i ++ )
{
scanf("%d", &a[i]);
if (hh <= tt && i - q[hh] + 1 > k) hh ++ ;
while (hh <= tt && a[q[tt]] >= a[i]) tt -- ;//更新队列,去除掉单调队列中没用的元素//保证队列里面前面的元素绝对<后面的元素
q[ ++ tt] = i;//每轮遍历都要存一个i到单调队列中,别忘了
if (i - k + 1 >= 0) printf("%d ", a[q[hh]]);
}
puts("");
//单调递减队列
hh = 0, tt = -1;//重置队列
for (int i = 0; i < n; i ++ )
{
scanf("%d", &a[i]);
if (hh <= tt && i - q[hh] + 1 > k) hh ++ ;
while (hh <= tt && a[q[tt]] <= a[i]) tt --;//更新队列,去除掉单调队列中没用的元素//保证队列里面前面的元素绝对>后面的元素
q[ ++ tt] = i;
if (i - k + 1 >= 0) printf("%d ", a[q[hh]]);
}
return 0;
}