目录
一. 单向链表(数组模拟)模板
#include<iostream>
using namespace std;
const int N = 100010;
// head 表示头节点的下标
// e[i] 表示节点 i 的值
// ne[i] 表示节点 i 的 next 指针是多少
// idx 储存当前已经用到了哪个点
int head, e[N], ne[N], idx;
// 初始化
void init(){
head = -1;
idx = 0;
}
// 将 x 插到头结点
void add_to_head(int x){
e[idx] = x;
ne[idx] = head;
head = idx;
idx ++;
}
// 将 x 插到下标是 k 的点后面
void add(int k, int x){
e[idx] = x;
ne[idx] = ne[k];
ne[k] = idx;
idx ++;
}
// 将下标是 k 的点后面的点删掉
void remove(int k){
ne[k] = ne[ne[k]];
}
int main(){
init();
add_to_head(1);
add_to_head(2);
add_to_head(3);
add(1, 4);
add(3, 6);
remove(2);
for (int i=head; i != -1; i = ne[i]) cout << e[i] << " ";
return 0;
}
二. 双向链表(数组模拟)模板
#include<iostream>
using namespace std;
const int N = 100010;
int n[N], l[N], r[N], idx;
// 初始化
void init(){
// 0 表示左端点, 1 表示右端点
r[0] = 1;
l[1] = 0;
idx = 2;
}
// 在下标是 k 的右边插入 x
void add(int k, int x){
n[idx] = x;
r[idx] = r[k];
l[idx] = k;
l[r[k]] = idx;
r[k] = idx;
idx ++;
}
// 删除下标是 k 的点
void remove(int k){
r[l[k]] = r[k];
l[r[k]] = l[k];
}
int main(){
init();
add(0, 1);
add(2, 2);
add(3, 3);
add(3, 4);
remove(2);
for (int i=r[0]; i!=1; i=r[i]) cout << n[i] << " ";
return 0;
}
三.单调栈
给一串序列:1 3 2 5 3 4;
判断每个数前面离它最近且比它小的数是多少;如果没有,输出 -1;
则会输出:-1 1 1 2 2 3。
#include<bits/stdc++.h>
using namespace std;
const int N = 100010;
int n;
int stk[N], tt;
int main()
{
cin.tie(0);
ios::sync_with_stdio(false);
cin >> n;
for (int i=0; i<n; i++){
int x;
cin >> x;
while (tt && stk[tt] >= x) tt --;
if (tt) cout << stk[tt] << " ";
else cout << -1 << " ";
stk[++ tt] = x;
}
return 0;
}
四.单调队列
给一串序列:1 3 2 -1 -5 2 -3 2;
给一个特定的长度 k = 3;判断每三个数中,最小的那个数,并将其输出;
则输出:1 -1 -5 -5 -5 -3。
#include<bits/stdc++.h>
using namespace std;
const int N = 100010;
int n, k;
int a[N];
int hh, tt = -1, q[N];
int main()
{
scanf("%d %d", &n, &k);
for (int i=0; i<n; i++) scanf("%d", &a[i]);
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;
}
五.KMP
给一串长为 n 的字符串 p = ab;
给一串长为 m 的字符串 s = sababababa,且 m >= n;
判断 p 在 s 中出现的所有位置;
则输出:1 3 5 7。
#include<iostream>
using namespace std;
const int N = 10010, M = 100010;
int n, m;
char p[N], s[M];
int ne[N];
int main(){
cin >> n >> p + 1 >> m >> s + 1;
//求next的过程
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;
}
//kmp 匹配过程
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];
}
}
return 0;
}
六. trie树(又名:字典树)
实现对字符串的快速插入和查找。
#include <bits/stdc++.h>
using namespace std;
const int N = 100010;
int son[N][26], cnt[N], idx; // 下标是 0 的点,即是根节点,又是空节点
char str[N];
void insert(char str[]){
int p = 0;
for (int i = 0; str[i]; i++){
int u = str[i] - 'a';
if (!son[p][u]) son[p][u] = ++ idx;
p = son[p][u];
}
cnt[p] ++;
}
int query(char str[]){
int p = 0;
for (int i =0; str[i]; i++){
int u = str[i] - 'a';
if (!son[p][u]) return 0;
p = son[p][u];
}
return cnt[p];
}
int main(){
int n;
scanf("%d", &n);
while (n --){
char op[2];
scanf("%s%s", op, str);
if (op[0] == 'I') insert(str);
else printf("%d\n", query(str));
}
return 0;
}
七.并查集
#include <iostream>
using namespace std;
const int N = 100010;
int n, m;
int p[N];
// find 函数是最重要的部分
int find(int x){ //返回 x 的祖宗节点 + 路径压缩
if (p[x] != x) p[x] = find(p[x]);
return p[x];
}
int main(){
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) p[i] = i;
while (m --){
char op[2];
int a, b;
scanf("%s%d%d", op, &a, &b);
if (op[0] == 'M') p[find(a)] = find(b);
else{
if (find(a) == find(b)) puts("Yes");
else puts("No");
}
}
return 0;
}
八.堆(小堆顶)
#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
const int N = 100010;
int h[N], ph[N], hp[N], size;
void heap_swap(int a, int b)
{
swap(ph[hp[a]], ph[hp[b]]);
swap(hp[a], hp[b]);
swap(h[a], h[b]);
}
void down(int u)
{
int t = u;
if (u * 2 <= size && h[u * 2] < h[t]) t = u * 2;
if (u * 2 + 1 <= size && h[u * 2 + 1] < h[t]) t = u * 2 + 1;
if (u != t)
{
heap_swap(u, t);
down(t);
}
}
void up(int u)
{
while (u / 2 && h[u / 2] > h[u])
{
heap_swap(u / 2, u);
u /= 2;
}
}
int main()
{
int n, m = 0;
cin >> n;
while (n--)
{
char op[10];
int k, x;
cin >> op;
if (!strcmp(op, "I"))
{
cin >> x;
size ++;
m ++;
ph[m] = size, hp[size] = m;
h[size] = x;
up(size);
}
else if (!strcmp(op, "PM")) cout << h[1];
else if (!strcmp(op, "DM"))
{
heap_swap(1, size);
size --;
down(1);
}
else if (!strcmp(op, "D"))
{
cin >> k;
k = ph[k];
heap_swap(k, size);
size --;
down(k), up(k);
}
else
{
cin >> k >> x;
k = ph[k];
h[k] = x;
down(k), up(k);
}
}
return 0;
}
九. 哈希表
拉链法
#include <cstring>
#include <iostream>
using namespace std;
const int N = 100003;
int h[N], e[N], ne[N], idx;
void insert (int x) //向表中插入元素
{
int k = (x % N + N) % N;
e[idx] = x;
ne[idx] = h[k];
h[k] = idx ++;
}
bool find (int x) //查找表中的元素
{
int k = (x % N + N) % N;
for (int i = h[k]; i!=-1; i = ne[i])
if (e[i] == x)
return true;
return false;
}
int main()
{
int n;
cin >> n;
memset(h, -1, sizeof h);
while (n--)
{
char op[2];
int x;
cin >> op >> x;
if (*op == 'I') insert(x);
else
{
if (find(x)) puts("yes");
else puts("no");
}
}
return 0;
}
开放寻址法
#include <cstring>
#include <iostream>
using namespace std;
const int N = 200003, null = 0x3f3f3f3f; // N一般开到数据范围的 2~3 倍(解决冲突)
int h[N];
int find (int x) // 如果 x 在表中,返回 x 的位置;否则返回 x 应该在的位置
{
int k = (x % N + N) % N;
while (h[k]!=null && h[k]!=x)
{
k ++;
if (k == N) k = 0;
}
return k;
}
int main()
{
int n;
cin >> n;
memset(h, 0x3f, sizeof h);
while (n--)
{
char op[2];
int x;
scanf("%s%d", op, &x);
int k = find (x);
if (*op == 'I') h[k] = x;
else
{
if (h[k] != null) puts("yes");
else puts("no");
}
}
for (int i=1;i<=5; i++) cout << h[i] << " ";
return 0;
}
字符串前缀哈希法
#include<iostream>
#include<cstring>
using namespace std;
typedef unsigned long long ULL; // 超出这个范围,就相当于取模操作
const int N = 100010, P = 131; // P 是进制,经验值取 131 或 13331 的 冲突最少
int n, m;
char str[N];
ULL h[N], p[N];
ULL get(int l, int r)
{
return h[r] - h[l - 1] * p[r - l + 1];
}
int main()
{
scanf("%d%d%s", &n, &m, str + 1);
p[0] = 1;
for (int i=1; i<=n; i++)
{
p[i] = p[i-1] * P;
h[i] = h[i-1] * P + str[i];
}
while (m --)
{
int l1, r1, l2, r2;
scanf ("%d%d%d%d", &l1, &r1, &l2, &r2);
if (get(l1, r1) == get(l2, r2)) puts("yes");
else puts("no");
}
return 0;
}