-
基础思路(不标记):解决题目的整体思路。
- 实现(不标记,除非题目完全考察编程语言实现):题目的要求是实现某个操作,根据题目描述将该操作实现。
- 模拟:题目的要求是计算某个结果,通过模拟题目描述的操作来计算该结果。
- 归纳:通过分析题目答案的规律性来得到答案。(
LC-0335
) - 枚举:枚举的思想是不断地猜测,从可能的集合中一一尝试,然后再判断题目的条件是否成立。
- 搜索:对状态空间进行枚举,通过穷尽所有的可能来找到最优解,或者统计合法解的数量。与枚举区别于,搜索是在状态空间中进行枚举。“深度优先搜索-图论”和“广度优先搜索-图论”并不属于搜索。
- 分治:“分而治之”。将复杂的问题分成两个或多个相同或相似的子问题,知道最后子问题可以简单的直接求解,原问题的解既子问题的解的合并。
- 贪心:“贪心决策”。每一步行动都选取当前最优的操作,而不考虑对以后造成的影响。与动态规划的区别在于,贪心算法在每一步都做出了选择,而动态规划则在每一步都记录的每种选择的结果。
- 排序&贪心解法:先排序再使用贪心解法的方法;其中排序仅是为了能够使用贪心解法。
- 后悔的贪心解法:无论当前选项是否为最优都接受,然后进行比较,如果选择之后不是最优的,则反悔并舍弃掉这个选项。
- 动态规划
- 背包 DP
- 区间 DP
- DAG上的 DP
- 树形 DP
- 状压 DP
- 数位 DP
- 插头 DP
- 计数 DP
- 动态 DP
- 概率 DP
- 倍增:通过倍增使线性的处理转化为对数级的处理。(参考资料1)
-
数据结构(不标记)
- 数组:如果是用数组实现的哈希表,标记为哈希表而不是数组。(通常是用于存储数据的数据结构)
- 二维数组
- 字符串:(通常是用于存储数据的数据结构)
- 链表:链表采用节点来分配每一个元素,每个结点维护一个指向它的元素的引用,并含一个或多个指向相邻节点的引用。(通常是用于存储数据的数据结构)
- 单向链表(不标记):每个结点仅存储指向其后继节点的引用。
- 相交链表:两个单向链表相交于某个结点。
- 有环链表:单向链表的最后一个结点指向单向链表中的某个节点(也可能是循环链表)。如果最后一个结点不是固定指向第一个结点,则标记为有环链表。
- 双向链表:每个结点存储指向其先驱节点以及后继结点的引用。
- 循环链表:每个结点仅存储指向其后继结点的引用,但是最后一个结点指向第一个结点。
- 单向链表(不标记):每个结点仅存储指向其后继节点的引用。
- 树(通常是用于存储数据的数据结构)
- 二叉树
- 二叉搜索树
- 二叉树
- 图(通常是用于存储数据的数据结构)
- 无向图
- 有向图
- 有向无环图
- 栈(通常是用于解决问题的数据结构)
- 单调栈
- 队列(通常是用于解决问题的数据结构)
- 单调队列
- 双端队列
- 哈希表:不考虑哈希表的具体实现方法,使用数组或哈希表实现均可。(通常是用于解决问题的数据结构)
- 哈希集合(不标记):一般用于判断元素是否重复。
- 哈希映射(不标记):一般用于存储键值对。
- 堆 / 优先队列(通常是用于解决问题的数据结构)
- AVL树(通常是用于解决问题的数据结构)
- 红黑树(通常是用于解决问题的数据结构)
- 有序数组(通常是用于解决问题的数据结构)
- 有序集合(通常是用于解决问题的数据结构)
- 树状数组:Binary Indexed Tree (BIT)。(通常是用于解决问题的数据结构)
- 后缀数组(通常是用于解决问题的数据结构)
- 线段树(通常是用于解决问题的数据结构)
- 并查集(通常是用于解决问题的数据结构)
- 字典树(通常是用于解决问题的数据结构)
- KD树(通常是用于解决问题的数据结构)
- 数组:如果是用数组实现的哈希表,标记为哈希表而不是数组。(通常是用于存储数据的数据结构)
-
算法(不标记):解决某个具体问题的具体方法。
- 字符串搜索(不标记)
- 字符串匹配
- 前缀函数
- KMP算法
- Manacher算法:用 O ( n ) O(n) O(n) 的时间复杂度,计算以每个字符为中心的最大回文半径。我们认为Manacher算法本质上也是将原问题分解为相对简单的子问题的方式来求解复杂问题的方法,是一种基于动态规划思路下的方法。因此,Manacher算法也需要标记“动态规划“标签。(参考资料1)
- 图论(不标记)
- 拓扑排序
- 最短路
- 欧拉回路
- 最小生成树
- 强联通分量
- 双连通分量
- 排序算法(如果不要求具体排序方法,则标记)
- 计数排序
- 桶排序
- 基数排序
- 归并排序
- 随机化(不标记)
- Fisher-Yates 洗牌算法:使用 O ( n ) O(n) O(n) 的时间复杂度随机化打乱数组。
- 字符串搜索(不标记)
-
策略(不标记):解决题目或题目中某个部分的具体思路。
- 双指针:与滑动窗口的区别在于,双指针只考虑两个指针指向的元素而不考虑两个指针之间的元素。两个指针的移动方向可以是相同的也可以是不同的。
- 排序&双指针:先排序再使用双指针的方法;其中排序仅是为了能够使用双指针。
- 快慢针:一般适用于链表,可以用于判断链表是否循环。一个指针每次移动一次,一个指针每次移动两次。
- 滑动窗口:与双指针的区别在于,滑动窗口需考虑两个指针内包含的元素。两个指针的移动方向是相同的。滑动窗口可以是定长的、也可以是变长的。
- 前缀和:【与差分相对】前缀和即将数列前
n
n
n 项的某个特征(和/积/异或和等)。前缀和是一种预处理方法,可以先用
O
(
n
)
O(n)
O(n) 复杂度的初始化,使后续每次查询的复杂度降为
O
(
1
)
O(1)
O(1)。
- 二维前缀和
- 高维前缀和
- 树上前缀和
- 差分:【与前缀和相对】差分数组记录数列第 n n n 项中某个特征的变化量。差分是一种后处理方法,每次修改仅做出开始和结束两个标记,时间复杂度为 O ( 1 ) O(1) O(1),标记完成后用 O ( n ) O(n) O(n) 的复杂度完成后处理。
- 查找策略(不标记):在具有一定规律的数值中查找指定要求的值。
- 二分查找:通过二分的方法,每次通过判断中间值是否符合要求,筛除一半的值并最终找到目标值。
- 三分查找:通过三分的方法,每次通过判断两个三分位点的关系,筛除三分之一的值并最终找到目标值。
- 快速选择:快速选择使用了“分治”的思路,也需要标记“分治”。
- 搜索策略(不标记)
- 记忆化搜索:一般来说,标记为记忆化搜索也可以标记动态规划。
- 二分搜索:二分搜索法可以用来查找满足某种条件的最大(最小)的值。相较于“二分查找”,“二分搜索”更倾向于在广义的有序中进行搜索。
- 回溯:回溯是一种经常被用在深度优先搜索和广度优先搜索中的技巧。其核心思路是“走不通就回头”。
- 深度优先搜索&广度优先搜索(不标记):
- 深度优先搜索-搜索:使用深度优先搜索对状态空间进行枚举,通过穷尽所有的可能来找到最优解。
- 广度优先搜索-搜索:使用广度优先搜索对状态空间进行枚举,通过穷尽所有的可能来找到最优解。
- 深度优先搜索-图论:在树、图、矩阵或类似数据结构中使用深度优先搜索方法遍历。
- 广度优先搜索-图论:在树、图、矩阵或类似数据结构中使用广度优先搜索方法遍历。
- 状态压缩
- 离散化
- 扫描线
- 离线算法
- 排序:题目没有要求排序,但可以通过排序来简化问题的策略。
- 双指针:与滑动窗口的区别在于,双指针只考虑两个指针指向的元素而不考虑两个指针之间的元素。两个指针的移动方向可以是相同的也可以是不同的。
-
技巧(不标记):实现某种策略的具体方法。
- 递归:在函数的定义中使用函数自身的方法。递归作为一种基础方法,在其他方法(例如深度优先搜索或记忆化搜索)中用到递归,如果递归的方法是较好的或主流的,则应被标记。
- 位运算
- 数字电路设计
- 哈希函数(不标记)
- 滚动哈希
- 字符串哈希
- 哈希表计数:使用数组或哈希表统计元素出现频次,即哈希表中的值为元素出现频次,类似于 Python 的
collections.Counter
。 - 字符串操作:字符串的操作技巧。
-
数学(除作为数学综合含义外,不标记)
- 四则运算(如果已经有了数学标签,那么即使用到四则运算也不标记四则运算):需要使用加、减、乘、除、取模的基础运算。
- 基本初等函数:幂函数、指数函数、对数函数、三角函数、反三角函数
- 二进制运算
- 概率统计
- 组合数学
- 矩阵
- 博弈
- 随机化
- 随机选择:随机抽取一批数据中的一个。
- 水塘抽样
- 拒绝抽样
- 几何
- 数论
- 快速幂
- 矩阵快速幂
- 牛顿迭代法
-
设计(不标记)
- 数据结构设计:设计一种支持某些操作的特定数据结构。
- 预处理设计:对数据进行预处理以支持某种频繁的查询。
- 数据流设计:数据中的题目以数据流形式输出,这种输入主要是为了不能使用离线算法计算。
- 迭代器设计
-
交互
-
脑筋急转弯