算法基础课
数据结构
单链表
=#include <iostream>
using namespace std;
const int N = 100010;
int head, e[N], ne[N], idx;
void init()
{
head = -1;
idx = 0;
}
void add_to_head(int x)
{
e[idx] = x, ne[idx] = head, head = idx ++ ;
}
void add(int k, int x)
{
e[idx] = x, ne[idx] = ne[k], ne[k] = idx ++ ;
}
void remove(int k)
{
ne[k] = ne[ne[k]];
}
int main()
{
int m;
cin >> m;
init();
while (m -- )
{
int k, x;
char op;
cin >> op;
if (op == 'H')
{
cin >> x;
add_to_head(x);
}
else if (op == 'D')
{
cin >> k;
if (!k) head = ne[head];
else remove(k - 1);
}
else
{
cin >> k >> x;
add(k - 1, x);
}
}
for (int i = head; i != -1; i = ne[i]) cout << e[i] << ' ';
cout << endl;
return 0;
}
双链表
#include <iostream>
using namespace std;
const int N = 100010;
int m;
int e[N], l[N], r[N], idx;
void insert(int a, int x)
{
e[idx] = x;
l[idx] = a, r[idx] = r[a];
l[r[a]] = idx, r[a] = idx ++ ;
}
void remove(int a)
{
l[r[a]] = l[a];
r[l[a]] = r[a];
}
int main()
{
cin >> m;
r[0] = 1, l[1] = 0;
idx = 2;
while (m -- )
{
string op;
cin >> op;
int k, x;
if (op == "L")
{
cin >> x;
insert(0, x);
}
else if (op == "R")
{
cin >> x;
insert(l[1], x);
}
else if (op == "D")
{
cin >> k;
remove(k + 1);
}
else if (op == "IL")
{
cin >> k >> x;
insert(l[k + 1], x);
}
else
{
cin >> k >> x;
insert(k + 1, x);
}
}
for (int i = r[0]; i != 1; i = r[i]) cout << e[i] << ' ';
cout << endl;
return 0;
}
栈
模拟栈
#include <iostream>
using namespace std;
const int N = 100010;
int st[N];
int top = -1;
int n;
int main()
{
cin >> n;
while(n--)
{
string s;
cin >> s;
if(s == "push")
{
int a;
cin >> a;
st[++top] = a;
}
if(s == "pop")
{
top --;
}
if(s == "query")
{
cout << st[top] << endl;
}
if(s == "empty")
{
cout << (top == -1 ? "YES" : "NO") << endl;
}
}
}
表达式求值
#include <iostream>
#include <stack>
#include <string>
#include <unordered_map>
using namespace std;
stack<int> num;
stack<char> op;
unordered_map<char, int> h{ {'+', 1}, {'-', 1}, {'*',2}, {'/', 2} };
void eval()
{
int a = num.top();
num.pop();
int b = num.top();
num.pop();
char p = op.top();
op.pop();
int r = 0;
if (p == '+') r = b + a;
if (p == '-') r = b - a;
if (p == '*') r = b * a;
if (p == '/') r = b / a;
num.push(r);
}
int main()
{
string s;
cin >> s;
for (int i = 0; i < s.size(); i++)
{
if (isdigit(s[i]))
{
int x = 0, j = i;
while (j < s.size() && isdigit(s[j]))
{
x = x * 10 + s[j] - '0';
j++;
}
num.push(x);
i = j - 1;
}
else if (s[i] == '(')
{
op.push(s[i]);
}
else if (s[i] == ')')
{
while(op.top() != '(')
eval();
op.pop();
}
else
{
while (op.size() && h[op.top()] >= h[s[i]])
eval();
op.push(s[i]);
}
}
while (op.size()) eval();
cout << num.top() << endl;
return 0;
}
队列
模拟队列
#include <iostream>
using namespace std;
const int N = 100010;
int q[N];
int hh = 0;
int tt = -1;
int m;
string s;
void push(int x){
q[++tt] = x;
}
void pop(){
hh++;
}
void empty(){
if(tt >= hh) cout << "NO" << endl;
else cout << "YES" << endl;
}
void query (){
cout << q[hh] << endl;
}
int main(){
cin >> m;
while(m--){
cin >> s;
if(s == "push"){
int x;
cin >> x;
push(x);
}
if(s == "pop"){
pop();
}
if(s == "empty"){
empty();
}
if(s == "query"){
query();
}
}
}
单调栈
#include <iostream>
using namespace std;
const int N = 100010;
int stk[N], tt;
int main()
{
int n;
cin >> n;
while (n -- )
{
int x;
scanf("%d", &x);
while (tt && stk[tt] >= x) tt -- ;
if (!tt) printf("-1 ");
else printf("%d ", stk[tt]);
stk[ ++ tt] = x;
}
return 0;
}
单调队列
#include <iostream>
using namespace std;
const int N = 1000100;
int a[N], q[N], n, k;
int front = 0, tail = -1;
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 (front <= tail && i - k + 1 > q[front]) front++;
while (front <= tail && a[i] <= a[q[tail]]) tail--;
q[++tail] = i;
if (i >= k - 1) printf("%d ", a[q[front]]);
}
printf("\n");
front = 0, tail = -1;
for (int i = 0; i < n; i++) {
if (front <= tail && i - k + 1 > q[front]) front++;
while (front <= tail && a[i] >= a[q[tail]]) tail--;
q[++tail] = i;
if (i >= k - 1) printf("%d ", a[q[front]]);
}
}
KMP
#include <iostream>
using namespace std;
const int N = 100010, M = 1000010;
int n, m;
int ne[N];
char s[M], p[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];
}
}
return 0;
}
Trie (专门用来处理存储字符串的集合问题)
Trie字符串统计
#include <iostream>
using namespace std;
const int N = 100010;
int son[N][26], cnt[N], idx;
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 == 'I') insert(str);
else printf("%d\n", query(str));
}
return 0;
}
最大异或对
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 100010, M = 3100010;
int n;
int a[N], son[M][2], idx;
void insert(int x)
{
int p = 0;
for (int i = 30; i >= 0; i -- )
{
int &s = son[p][x >> i & 1];
if (!s) s = ++ idx;
p = s;
}
}
int search(int x)
{
int p = 0, res = 0;
for (int i = 30; i >= 0; i -- )
{
int s = x >> i & 1;
if (son[p][!s])
{
res += 1 << i;
p = son[p][!s];
}
else p = son[p][s];
}
return res;
}
int main()
{
scanf("%d", &n);
for (int i = 0; i < n; i ++ )
{
scanf("%d", &a[i]);
insert(a[i]);
}
int res = 0;
for (int i = 0; i < n; i ++ ) res = max(res, search(a[i]));
printf("%d\n", res);
return 0;
}
并查集
合并集合
#include<bits/stdc++.h>
using namespace std;
const int N = 100010;
int p[N];
int n,m;
int find(int 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 -- )
{
int a,b;
char op[2];
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<bits/stdc++.h>
using namespace std;
const int N = 100010;
int p[N],cnt[N];
int find(int x)
{
if(p[x]!=x) p[x]=find(p[x]);
return p[x];
}
int main()
{
int n,m;
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i ++ )
{
p[i]=i;
cnt[i]=1;
}
while (m -- )
{
string op;
cin>>op;
int a,b;
if(op=="C")
{
cin >> a>>b;
a=find(a),b=find(b);
if(a!=b)
{
p[a]=b;
cnt[b]+=cnt[a];
}
}
else if(op=="Q1")
{
cin >> a>>b;
if(find(a)==find(b)) puts("Yes");
else puts("No");
}
else
{
cin >> a;
int x=find(a);
cout << cnt[x]<<endl;
}
}
return 0;
}
食物链、
#include <iostream>
using namespace std;
const int N = 1e5 + 10;
int n, m;
int p[N], d[N];
int find(int x)
{
if (p[x] != x)
{
int t = find(p[x]);
d[x] += d[p[x]];
p[x] = t;
}
return p[x];
}
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i ++ ) p[i] = i;
int res = 0;
while (m -- )
{
int t, x, y;
scanf("%d%d%d", &t, &x, &y);
if (x > n || y > n) res ++ ;
else
{
int px = find(x), py = find(y);
if (t == 1)
{
if (px == py) {
if ((d[x] - d[y]) % 3) res ++ ;
} else {
p[px] = py;
d[px] = d[y] - d[x];
}
}
else
{
if (px == py) {
if ((d[x] - d[y] - 1) % 3) res ++ ;
} else {
p[px] = py;
d[px] = d[y] + 1 - d[x];
}
}
}
}
printf("%d\n", res);
return 0;
}
堆
堆排序
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 100010;
int n, m;
int h[N], cnt;
void down(int u)
{
int t = u;
if (u * 2 <= cnt && h[u * 2] < h[t]) t = u * 2;
if (u * 2 + 1 <= cnt && h[u * 2 + 1] < h[t]) t = u * 2 + 1;
if (u != t)
{
swap(h[u], h[t]);
down(t);
}
}
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i ++ ) scanf("%d", &h[i]);
cnt = n;
for (int i = n / 2; i; i -- ) down(i);
while (m -- )
{
printf("%d ", h[1]);
h[1] = h[cnt -- ];
down(1);
}
puts("");
return 0;
}
模拟堆
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1e5 + 10;
int heap[N], cnt;
int ph[N];
int hp[N];
void heap_swap(int a, int b) {
swap(ph[hp[a]], ph[hp[b]]);
swap(hp[a], hp[b]);
swap(heap[a], heap[b]);
}
void downAdjust(int u) {
int m = u;
if (u * 2 <= cnt && heap[u * 2] < heap[m]) m = u * 2;
if (u * 2 + 1 <= cnt && heap[u * 2 + 1] < heap[m]) m = u * 2 + 1;
if (u != m) {
heap_swap(u, m);
downAdjust(m);
}
}
void upAdjust(int u) {
while (u / 2 && heap[u / 2] > heap[u]) {
heap_swap(u, u / 2);
u /= 2;
}
}
int main() {
int index = 0;
int n = 0;
cin >> n;
while (n--) {
string op;
cin >> op;
int x, k;
if (op == "I") {
cin >> x;
cnt++;
index++;
ph[index] = cnt;
hp[cnt] = index;
heap[cnt]=x;
upAdjust(cnt);
} else if (op == "PM") {
cout << heap[1] << endl;
} else if (op == "DM") {
heap_swap(1, cnt);
cnt--;
downAdjust(1);
} else if (op == "D") {
cin >> k;
int pos = ph[k];
heap_swap(pos, cnt);
cnt--;
upAdjust(pos), downAdjust(pos);
} else if (op == "C") {
cin >> k >> x;
int pos = ph[k];
heap[pos] = x;
upAdjust(pos), downAdjust(pos);
}
}
return 0;
}
哈希表
模拟散列函数
#include <cstring>
#include <iostream>
using namespace std;
const int N = 200003, null = 0x3f3f3f3f;
int h[N];
int find(int x)
{
int t = (x % N + N) % N;
while (h[t] != null && h[t] != x)
{
t ++ ;
if (t == N) t = 0;
}
return t;
}
int main()
{
memset(h, 0x3f, sizeof h);
int n;
scanf("%d", &n);
while (n -- )
{
char op[2];
int x;
scanf("%s%d", op, &x);
if (*op == 'I') h[find(x)] = x;
else
{
if (h[find(x)] == null) puts("No");
else puts("Yes");
}
}
return 0;
}
字符串哈希
#include<iostream>
#include<cstdio>
#include<string>
using namespace std;
typedef unsigned long long ULL;
const int N = 1e5+5,P = 131;
ULL h[N],p[N];
ULL query(int l,int r){
return h[r] - h[l-1]*p[r-l+1];
}
int main(){
int n,m;
cin>>n>>m;
string x;
cin>>x;
p[0] = 1;
h[0] = 0;
for(int i=0;i<n;i++){
p[i+1] = p[i]*P;
h[i+1] = h[i]*P +x[i];
}
while(m--){
int l1,r1,l2,r2;
cin>>l1>>r1>>l2>>r2;
if(query(l1,r1) == query(l2,r2)) printf("Yes\n");
else printf("No\n");
}
return 0;
}