目录
1、队列
1.1 模板
1)普通队列
// hh 表示队头,tt表示队尾
int q[N], hh = 0, tt = -1;
// 向队尾插入一个数
q[ ++ tt] = x;
// 从队头弹出一个数
hh ++ ;
// 队头的值
q[hh];
// 判断队列是否为空,如果 hh <= tt,则表示不为空
if (hh <= tt)
{
}
2)循环队列
// hh 表示队头,tt表示队尾的后一个位置
int q[N], hh = 0, tt = 0;
// 向队尾插入一个数
q[tt ++ ] = x;
if (tt == N) tt = 0;
// 从队头弹出一个数
hh ++ ;
if (hh == N) hh = 0;
// 队头的值
q[hh];
// 判断队列是否为空,如果hh != tt,则表示不为空
if (hh != tt)
{
}
1.2 例题
题目来源:AcWing
题目链接:AcWing 829. 模拟队列
代码展示:
#include <iostream>
using namespace std;
const int N = 1e5 + 10;
int q[N], hh = 0, tt = -1;
int main()
{
int m;
cin >> m;
while (m -- )
{
string op;
cin >> op;
if (op == "push")
{
int x;
cin >> x;
q[ ++ tt] = x;
}
else if (op == "pop") hh ++;
else if (op == "query") cout << q[hh] << endl;
else
{
if (hh <= tt) cout << "NO" << endl;
else cout << "YES" << endl;
}
}
return 0;
}
2、单调栈
2.1 模板
常见模型:找出每个数左边离它最近的比它大/小的数
int tt = 0;
for (int i = 1; i <= n; i ++ )
{
while (tt && check(stk[tt], i)) tt -- ;
stk[ ++ tt] = i;
}
2.2 例题
题目来源:AcWing
题目链接:AcWing 830. 单调栈
代码展示:
#include <iostream>
using namespace std;
const int N = 1e5 + 10;
int stk[N], tt = 0;
int main()
{
int m;
cin >> m;
while (m -- )
{
int x;
cin >> x;
while (tt && stk[tt] >= x) tt --;
if (!tt) cout << -1 << " ";
else cout << stk[tt] << " ";
stk[ ++ tt] = x;
}
return 0;
}
3、单调队列
3.1 模板
常见模型:找出滑动窗口中的最大值/最小值
int hh = 0, tt = -1;
for (int i = 0; i < n; i ++ )
{
while (hh <= tt && check_out(q[hh])) hh ++ ; // 判断队头是否滑出窗口
while (hh <= tt && check(q[tt], i)) tt -- ;
q[ ++ tt] = i;
}
3.2 例题
题目来源:AcWing
题目链接:AcWing 154. 滑动窗口
代码展示:
#include <iostream>
using namespace std;
const int N = 1e6 + 10;
int a[N], q[N];
int main()
{
int n, k;
cin >> 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]]);
}
return 0;
}
4、KMP
4.1 模板
// s[]是长文本,p[]是模式串,n是s的长度,m是p的长度
求模式串的Next数组:
for (int i = 2, j = 0; i <= m; i ++ )
{
while (j && p[i] != p[j + 1]) j = ne[j];
if (p[i] == p[j + 1]) j ++ ;
ne[i] = j;
}
// 匹配
for (int i = 1, j = 0; i <= n; i ++ )
{
while (j && s[i] != p[j + 1]) j = ne[j];
if (s[i] == p[j + 1]) j ++ ;
if (j == m)
{
j = ne[j];
// 匹配成功后的逻辑
}
}
4.2 例题
题目来源:AcWing
题目链接:AcWing 831. KMP字符串
代码展示:
#include <iostream>
using namespace std;
const int N = 1e5 + 10, M = 1e6 + 10;
int n, m;
char p[N], s[M];
int ne[N];
int main()
{
cin >> n >> p + 1 >> m >> s + 1;
for (int i = 2, j = 0; i <= n; i ++ )
{
while (j && p[i] != p[j + 1]) j = ne[j];
if (p[i] == p[j + 1]) j ++ ;
ne[i] = j;
}
for (int i = 1, j = 0; i <= m; i ++ )
{
while (j && s[i] != p[j + 1]) j = ne[j];
if (s[i] == p[j + 1]) j ++ ;
if (j == n)
{
printf("%d ", i - n);
j = ne[j];
}
}
}