摘要:
树与图的DFS与BFS 树与图的DFS与BFS DFS BFS 首先,树是一种特殊结构的图,所以树与图的存储是相同的,而图又分为有向图与无向图,对无向图我们可以在两个点之间添加两条边。 有向图的存储方式主要有两种 稀疏图(点多边少)一般用邻接表存储 稠密图(点少边多)一般用邻接矩阵存储。 在邻接表的 阅读全文
摘要:
宽度优先搜索 BFS 宽度优先搜索 BFS 走迷宫 八数码 宽度优先搜索每次扩展当前结点的所有相邻结点,所以需要一个队列来维护要扩展的结点。由于宽度优先搜索每次都是把所有能到的下一步搜完,所以能够得到最短路径的解,所以一些不带权求最短路径的问题也可以直接用BFS解决。 注意,在扩展结点的某个下一结点 阅读全文
摘要:
深度优先搜索DFS 深度优先搜索DFS 排列数字 n-皇后问题 按位搜索 按行搜索 深度优先搜索的思想简单来说就是“一条道走到黑”,也被称为“暴力搜索”,常用于解决需要给出所有方案的问题,因为它的搜索顺序就是能够得到一个完整的搜索路径(方案)后回溯再去搜索其它的方案。 排列数字 题目链接:AcWin 阅读全文
摘要:
哈希表(Hash) 哈希表(Hash) 拉链法(开散列) 开放寻址法 字符串哈希 Hash 表又称为散列表,一般由 Hash 函数(散列函数)与链表结构共同实现。与离散化思想类似,当我们要对若干复杂信息进行统计时,可以用 Hash 函致把这些复杂信息映射到一个容易维护的值城内。因为值域变简单、范围变 阅读全文
摘要:
堆 堆是一种数据结构,主要包含以下操作: 插入一个数:将该数插到最后的位置,进行一次up操作 求集合中的最小值:输出堆顶元素 删除任意一个元素:将要删除的元素与末尾元素交换,然后进行一次up和down操作 修改任意一个元素:将某位置的元素修改,然后进行一次up和down操作 删除最小值:交换堆顶元素 阅读全文
摘要:
并查集(Disjoint-Set) 并查集(Disjoint-Set)是一种可以动态维护若干个不重叠的集合,并支持合并与查询的数据结构。详细地说,并查集包括如下两个基本操作: Get,查询一个元素属于哪个集合。 Merge,把两个集合合并成一个大集合。 为了具体实现并查集这种数据结构,我们首先需要定 阅读全文
摘要:
Trie Trie(字典树)是一种用于实现字符串快速检索的多叉树结构。Trie 的每个节点都拥有若干个字符指针,若在插入或检索字符串时扫描到一个字符 c ,就沿着当前节点的 c 字符指针,走向该指针指向的节点。下面详细讨论 Trie 的基本操作过程: 初始化:一棵空 Trie 仅包含一个根结点,该点 阅读全文
摘要:
KMP KMP 算法,又称模式匹配算法,能够在线性时间内判定字符串 $P[1 \sim N]$ 是否为字符串 $S[1 \sim M]$ 的子串。并求出字符串 $P$ 在字符串 $S$ 中各次出现的位置。 首先,一个 $O(NM)$ 的朴素做法是,尝试枚举字符串 $S$ 中的每个位置 $i$,把字符 阅读全文
摘要:
单调队列 单调队列算法很多时候用手写的模拟队列比较方便,因为很多时候需要双口出队的队列,主要是在队尾也有删除元素的需求。而模拟队列都是游标移动来限定队列中的所有元素,所以用模拟队列很自然的可以做到双端队列的操作。 单调队列一个经典应用就是求滑动窗口里的最大(或者最小)值。 算法步骤: 把该滑出的滑出 阅读全文
摘要:
单调栈 题目链接:AcWing 830. 单调栈 时间复杂度:$O(N)$ #include <iostream> using namespace std; const int N = 1e5 + 10; int n; int stk[N], tt; // 数组模拟栈,栈顶指针默认为0(空) int 阅读全文
摘要:
队列 数组模拟队列 题目链接:AcWing 829. 模拟队列 #include <iostream> using namespace std; const int N = 100010; int n; int q[N]; int hh = 0, tt = -1; void push(int x) 阅读全文
摘要:
栈 数组模拟栈 题目链接:AcWing 828. 模拟栈 #include <iostream> using namespace std; const int N = 100010; int n; int stk[N], tt; void push(int x) { stk[++ tt] = x; 阅读全文
摘要:
双链表 题目链接:AcWing 827. 双链表 #include <iostream> using namespace std; const int N = 100010; int e[N], l[N], r[N], idx; void init() { // 头节点为0,尾节点为1,插入的节点标 阅读全文
摘要:
单链表 题目链接:AcWing 826. 单链表 #include <iostream> using namespace std; const int N = 100010; int n; int e[N], ne[N], head, idx; void init() { idx = 0; head 阅读全文
摘要:
区间合并 区间合并问题也是一个贪心问题,由于比较常用所以单独拿出来。区间合并的解决方法是,把所有区间按照左端点 $l$ 从小到大排序,然后维护一个当前正在处理的区间 $[st,ed]$,如果遍历到区间和维护的区间有交集,就合并(能合则合),没有交集的时候,当前维护的区间就变成这个遍历到的区间。 这里 阅读全文
摘要:
离散化 离散化是一种辅助解决问题的操作,当问题中涉及的数据范围非常大,但是实际使用到的数据是比较少的。并且问题的求解是和它范围里的其它数据有关系的,那么可以将这些可能使用到的数据放到一起,排序去重,就将它们映射到了一个新的较小的范围里。 例如,下面几个数是在 $(-\infty, \infty)$ 阅读全文
摘要:
位操作 lowbit原理 根据计算机负数表示的特点,如一个数字原码是10001000,他的负数表示形式是补码,也就是反码+1,反码是01110111,加一则是01111000,二者按位与得到了1000,就是我们想要的lowbit操作 题目链接:AcWing 801. 二进制中1的个数 #includ 阅读全文
摘要:
双指针算法 双指针算法的核心思想就是在序列上找到这样一个性质,序列上的一个指针 $j$ 随着另一个指针 $i$ 的移动,是单向移动的,不会发生回退,这样就能在移动指针 $i$ 的时候去移动指针 $j$。由于两个指针都最多只会把序列遍历一遍,所以时间复杂度往往是从 $O(n^2)$ 优化到 $O(n) 阅读全文
摘要:
前缀和与差分 前缀和与差分 一维前缀和 差分 一维前缀和 前缀和可以用于快速计算一个序列的区间和,也有很多问题里不是直接用前缀和,但是借用了前缀和的思想。 用 $s[i]$ 表示 $a[0]+a[1]+\dots+a[i]$ 的和(所以称为前缀和),那么要计算区间 $[l, r]$ 的和,也就是计算 阅读全文
摘要:
高精度 高精度 高精度加法 高精度减法 高精度乘法 高精度除法 高精度加法 题目链接:AcWing 791. 高精度加法 题目描述 给定两个正整数(不含前导 0),计算它们的和。 输入格式 共两行,每行包含一个整数。 输出格式 共一行,包含所求的和。 数据范围 $1 \le$ 整数长度 $\le 1 阅读全文