算法基础课相关代码模板
int head, e[N], ne[N], idx;
void init ()
{
head = -1 ;
idx = 0 ;
}
void insert (int a)
{
e[idx] = a, ne[idx] = head, head = idx ++ ;
}
void remove ()
{
head = ne[head];
}
int e[N], l[N], r[N], idx;
void init ()
{
r[0 ] = 1 , l[1 ] = 0 ;
idx = 2 ;
}
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 stk[N], tt = 0 ;
stk[ ++ tt] = x;
tt -- ;
stk[tt];
if (tt > 0 )
{
}
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)
{
}
常见模型:找出每个数左边离它最近的比它大/小的数
int tt = 0 ;
for (int i = 1 ; i <= n; i ++ )
{
while (tt && check (stk[tt], i)) tt -- ;
stk[ ++ tt] = i;
}
常见模型:找出滑动窗口中的最大值/最小值
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;
}
// 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];
// 匹配成功后的逻辑
}
}
int son[N][26 ], cnt[N], idx;
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];
}
(1 )朴素并查集:
int p[N];
int find (int x)
{
if (p[x] != x) p[x] = find (p[x]);
return p[x];
}
for (int i = 1 ; i <= n; i ++ ) p[i] = i;
p[find (a)] = find (b);
(2 )维护size的并查集:
int p[N], size[N];
int find (int x)
{
if (p[x] != x) p[x] = find (p[x]);
return p[x];
}
for (int i = 1 ; i <= n; i ++ )
{
p[i] = i;
size[i] = 1 ;
}
size[find (b)] += size[find (a)];
p[find (a)] = find (b);
(3 )维护到祖宗节点距离的并查集:
int p[N], d[N];
int find (int x)
{
if (p[x] != x)
{
int u = find (p[x]);
d[x] += d[p[x]];
p[x] = u;
}
return p[x];
}
for (int i = 1 ; i <= n; i ++ )
{
p[i] = i;
d[i] = 0 ;
}
p[find (a)] = find (b);
d[find (a)] = distance;
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] < h[u / 2 ])
{
heap_swap (u, u / 2 );
u >>= 1 ;
}
}
for (int i = n / 2 ; i; i -- ) down (i);
(1 ) 拉链法
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 ;
}
(2 ) 开放寻址法
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;
}
核心思想:将字符串看成P进制数,P的经验值是131 或13331 ,取这两个值的冲突概率低
小技巧:取模的数用2 ^64 ,这样直接用unsigned long long 存储,溢出的结果就是取模的结果
typedef unsigned long long ULL;
ULL h[N], p[N];
p[0 ] = 1 ;
for (int i = 1 ; i <= n; i ++ )
{
h[i] = h[i - 1 ] * P + str[i];
p[i] = p[i - 1 ] * P;
}
ULL get (int l, int r)
{
return h[r] - h[l - 1 ] * p[r - l + 1 ];
}
C++ STL简介
vector, 变长数组,倍增的思想
size() 返回元素个数
empty() 返回是否为空
clear() 清空
front()/back()
push_back()/pop_back()
begin()/end()
[]
支持比较运算,按字典序
pair<int , int >
first, 第一个元素
second, 第二个元素
支持比较运算,以first为第一关键字,以second为第二关键字(字典序)
string,字符串
size()/length () 返回字符串长度
empty()
clear()
substr (起始下标,(子串长度)) 返回子串
c_str() 返回字符串所在字符数组的起始地址
queue, 队列
size()
empty()
push () 向队尾插入一个元素
front() 返回队头元素
back() 返回队尾元素
pop () 弹出队头元素
priority_queue, 优先队列,默认是大根堆
size()
empty()
push () 插入一个元素
top() 返回堆顶元素
pop () 弹出堆顶元素
定义成小根堆的方式:priority_queue<int , vector<int >, greater<int >> q ;
stack, 栈
size()
empty()
push () 向栈顶插入一个元素
top() 返回栈顶元素
pop () 弹出栈顶元素
deque, 双端队列
size()
empty()
clear()
front()/back()
push_back()/pop_back()
push_front()/pop_front()
begin()/end()
[]
set, map , multiset, multimap, 基于平衡二叉树(红黑树),动态维护有序序列
size()
empty()
clear()
begin()/end()
++, -- 返回前驱和后继,时间复杂度 O(logn)
set/multiset
insert() 插入一个数
find() 查找一个数
count() 返回某一个数的个数
erase()
(1 ) 输入是一个数x ,删除所有x O(k + logn)
(2 ) 输入一个迭代器,删除这个迭代器
lower_bound()/upper_bound()
lower_bound(x ) 返回大于等于x 的最小的数的迭代器
upper_bound(x ) 返回大于x 的最小的数的迭代器
map /multimap
insert() 插入的数是一个pair
erase() 输入的参数是pair或者迭代器
find()
[] 注意multimap不支持此操作。 时间复杂度是 O(logn)
lower_bound()/upper_bound()
unordered_set, unordered_map, unordered_multiset, unordered_multimap, 哈希表
和上面类似,增删改查的时间复杂度是 O(1 )
不支持 lower_bound()/upper_bound(), 迭代器的++,--
bitset, 圧位
bitset<10000 > s;
~, &, |, ^
>>, <<
==, !=
[]
count() 返回有多少个1
any() 判断是否至少有一个1
none() 判断是否全为0
set() 把所有位置成1
set(k, v) 将第k位变成v
reset () 把所有位变成0
flip() 等价于~
flip(k) 把第k位取反
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!