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指向的位置
head = idx; // head指向插入新指针的位置
idx ++; // idx指向下一个位置
}
将x插到下标是k的点后面void add(int k, int x) {e[idx] = x; // 存新指针的值
ne[idx] = ne[k]; // 新指针指向k点的下一个位置
ne[k] = idx; // k点的下一个位置指向新插入点的位置
idx ++; // idx指向下一个位置
}
将头节点删除,需要保证头节点存在void remove () {head = ne[head];
}
将下标是k的点后面的点删掉void remove(int k) {ne[k] = ne[ne[k]];
}
遍历链表for(int i = head; i != -1; i = ne[i])
2. 双链表int e[N], l[N], r[N], idx;
在点a的右边插入xvoid add(int a, int x) {e[idx] = x;
l[idx] = a, r[idx] = r[a];
l[r[a]] = idx, r[a] = idx ++;
}
删除点avoid remove(int a) {l[r[a]] = l[a];
r[l[a]] = r[a];
}
遍历链表for (int i = r[0]; i != 1; i = r[i])
3. 栈
插入:stk [++ tt] = x;
弹出:tt --;
判断栈是否为空:if(tt >0) not empty;
else empty;
查询栈顶:stk[tt]; // tt存的栈顶元素
4. 队列
在队尾插入元素,在队头弹出元素:int q[N], hh, tt = -1; // hh表示队头,tt表示队尾
插入:q[++ tt] = x;
弹出:hh ++;
判断队列是否为空:if(hh<= tt) not empty
else empty
取出队头元素:q[hh];
取出队尾元素:q[tt];
5. 单调栈常见模型:找出每个数左边离它最近的比它大/小的数
int tt = 0;
for (int i = 1; i<= n; i ++ ) {while (tt && check(stk[tt], i)) {tt -- ;
}
stk[ ++ tt] = i;
}
6. 单调队列常见模型:找出滑动窗口中的大值/最小值
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;
}
7. KMP// 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];
// 匹配成功后的逻辑
}
}
8. Trieint son[N][26], cnt[N], idx;
// 0号点既是根节点,又是空节点
// son[][]存储树中每个节点的子节点
// cnt[]存储以每个节点结尾的单词数量
// 插入一个字符串
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];
}
9. 并查集
朴素并查集:int p[N]; //存储每个点的祖宗节点
// 返回x的祖宗节点
int find(int x) {if (p[x] != x) {p[x] = find(p[x]);
}
return p[x];
}
// 初始化,假定节点编号是1~n
for (int i = 1; i<= n; i ++ ) {p[i] = i;
}
// 合并a和b所在的两个集合:
p[find(a)] = find(b);
维护size的并查集:int p[N], size[N];
//p[]存储每个点的祖宗节点, size[]只有祖宗节点的有意义,表示祖宗节点所在集合中的点的数量
// 返回x的祖宗节点
int find(int x) {if (p[x] != x) {p[x] = find(p[x]);
}
return p[x];
}
// 初始化,假定节点编号是1~n
for (int i = 1; i<= n; i ++ ) {p[i] = i;
size[i] = 1;
}
// 合并a和b所在的两个集合:
size[find(b)] += size[find(a)];
p[find(a)] = find(b);
维护到祖宗节点距离的并查集:int p[N], d[N];
//p[]存储每个点的祖宗节点, d[x]存储x到p[x]的距离
// 返回x的祖宗节点
int find(int x) {if (p[x] != x) {int u = find(p[x]);
d[x] += d[p[x]];
p[x] = u;
}
return p[x];
}
// 初始化,假定节点编号是1~n
for (int i = 1; i<= n; i ++ ) {p[i] = i;
d[i] = 0;
}
// 合并a和b所在的两个集合:
p[find(a)] = find(b);
d[find(a)] = distance; // 根据具体问题,初始化find(a)的偏移量
[例题]AcWing 1250. 格子游戏
AcWing 1252. 搭配购买
AcWing 237. 程序自动分析
// h[N]存储堆中的值, h[1]是堆顶,x的左儿子是2x, 右儿子是2x + 1
// ph[k]存储第k个插入的点在堆中的位置
// hp[k]存储堆中下标是k的点是第几个插入的
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;
}
}
// O(n)建堆
for (int i = n / 2; i; i -- ) {down(i);
}
二叉堆
例题acwing 148 合并果子
11. 哈希表 拉链法(N = 100003)int h[N], e[N], ne[N], idx;//槽,链表值,下一个位置,当前用到哪个位置
void insert(int x) {int k = (x % N + N) % 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;
}
开放寻址法(N=200003)int h[N]; // 槽
int find(int x) {// 如果x在哈希表存在,返回x的位置,如果不存在,返回x应该存贮的位置
int k = (x % N + N) % N;
while(h[k] != null && h[k] != x){// 当前位置有人并且不是x
k ++;
if(k == N) { k = 0;//循环看第一个位置
}
}
return k;
}
12. STLvector
变长数组,利用倍增思想vectora;
返回元素个数a.size()
返回a是否为空 空true
, 非空false
a.empty()
清空vector
a.clear()
返回第一个数a.front()
返回最后一个数a.back()
在最后插入一个数a.push_back()
删除最后一个数a.pop_back()
迭代器第0个数
a.begin()
最后一个数的下一个数
a.end()
pair
存储二元组pairt;
元素p.first
p.second
三种元素pair>p
string
字符串string s
字符串长度a.size()
字符串是否为空a.empty()
清空字符串a.clear()
从起始位置开始的字符串a.substr(字串的起始位置,字串的长度)
queuq
队列queueq
队列长度q.size()
队列是否为空q.empty()
向队尾插入元素q.push()
返回队尾元素q.back()
弹出对头元素q.pop()
清空队列(没有clear
函数)q = queue();
priority_queue
优先队列,默认是大根堆priority_queueq
插入一个元素q.push()
返回堆顶元素q.top()
弹出堆顶元素q.pop()
变成小根堆方法一
priority_queueheap;
heap(-x);
方法二
priority_queue, greater>heap;
stack
栈stackq;
栈长度q.size()
栈是否为空q.empty()
向栈顶插入一个元素q.push()
返回栈顶元素q.top()
弹出栈顶元素q.pop()
deque
双端队列dequeq;
队列长度q.size()
队列是否为空q.empty()
清空队列q.clear()
返回队列的第一个元素q.front()
返回队列的最后一个元素q.back()
向队列最后插入一个元素q.push_back()
弹出队列最后一个元素q.pop_back()
向队首插入一个元素q.push_front()
从队首弹出元素q.pop_front()
迭代器第0个数
q.begin()
最后一个数的下一个数
q.end()
binary_search
查找某个元素是否出现binary_search(arr[],arr[]+size,x)
参数说明:arr[]:数组首地址
size:数组元素个数
x:需要查找的值
函数功能:在数组中以二分法检索的方式查找,若在数组中查找到indx元素则真,若查找不到则返回值是假
lower_bound
查找第一个大于或等于某个元素的位置返回查找元素的第一个可安插位置,也就是“元素值>=查找值”的第一个元素的位置
函数模板:lower_bound(arr[],arr[]+size,x)
参数说明:arr[] : 数组首地址
size : 数组元素的个数
x : 需要查找的值
函数功能:函数lower_bound()
在first
和last
的前闭后开区间进行二分查找,返回大于或等于val
的第一个元素的位置,如果所有元素都小于val
,则返回last
的位置,且last的位置是越界的!upper_bound
查找第一个大于某个元素的位置返回查找元素的最后一个可安插位置,也就是“元素值>查找值”的第一个元素的位置
函数模板 :upper_bound(arr[] , arr[]+size , x)
参数说明:arr[] : 数组首地址
size : 数组元素个数
x : 需要查找的值
函数功能 : 函数upper_bound()返回的在前闭后开区间查找的关键字的上界,返回大于val的第一个元素位置
13.树状数组int a[N];
int tr[N]; // 树状数组
int Greater[N], lower[N]; // Greater[i]表示比i大的数,lower[i]表示比i大的数
int lowbit(int x) {return x & -x;
}
void add(int x, int c) {// 树状数组的增加函数 为第x个数加上c,并且给它的父亲节点也加上,这里为了表示是否出现,所以加的是1
for (int i = x; i<= n; i += lowbit(i)) {tr[i] += c;
}
}
// 求前1~x个数的和,tr[x]存储的是区间[x − lowbit(x) + 1,x]出现的数的次数,题目说y1到yn是1到n的排列,所以这个sum是用来求1~x中出现的数的个数
int sum (int x) {// 树状数组的查询函数
int res = 0;
for (int i = x; i; i -= lowbit(i)) {res += tr[i];
}
return res;
}
[例题]AcWing 241. 楼兰图腾
AcWing 242. 一个简单的整数问题
AcWing 243. 一个简单的整数问题2
AcWing 244. 谜一样的牛
你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧