算法思维:思考问题的一种方式
方法论:万物皆朴素的第一性原理
几乎任何领域的任何问题的解决方案,都可以看作是“某个结构上的朴素方法的优化“。
计算机只能处理规模有限的问题,在给定规模且不考虑效率的情况下,问题一定存在朴素解法。具体手段有直接模拟 / 利用bit枚举 / 各种搜索算法等。
具体方法:从问题到解决方案
一般的问题我们有一般的思考方式,而特殊的问题经过总结可以形成特定的解决方案,供今后调用。这需要长时间的积累。
举出一些算法竞赛中常用的问题——解决方案的思路:
-
若问题具备 ”线性多维逆序“ 结构,则考虑 CDQ分治。
-
若问题具备 ”元素唯一归属于某集合“ 结构,则考虑并查集。
-
若问题具备 ”连通性“ 结构,则考虑搜索 / 并查集。
-
若问题具备 ”记录数据未来使用“,则考虑哈希表。
-
若问题具备 “FILO / 可规约” 结构,则考虑栈。
-
若问题具备 ”线性结构上地最远/近最大/小元素“ 结构,则考虑单调栈。
-
若问题具备 ”FIFO“ 结构,考虑队列。
-
若问题具备 ”动态维护滑动窗口“ 结构,考虑单调队列。
-
若问题具备 ”字符串” 结构,则考虑如下做法:
- 若问题具备 ”字符串匹配“ 结构,则考虑如下做法:
- 若为线性结构,考虑KMP
- 若为Trie结构,考虑AC自动机
- 若问题具备 ”求最长回文子串” 结构,则考虑Mancher算法。
- 若问题具备 ”字符串匹配“ 结构,则考虑如下做法:
-
若问题具备 “某节点只有一个父节点” 结构,考虑树结构的如下做法:
- 若问题具备 “树的重心/直径/中心/最近公共祖先” 结构,则按经典算法处理。
- 若问题具备 “子树的相同问题” 结构,则考虑递归。
- 若问题具备 “子树的相似问题” 结构,则考虑树形Dp。
- 若问题具备 “对树的操作在区间上简单” 结构,则考虑 树链剖分 + 区间维护
-
若问题具备 “序无关 / 要求某种序” 结构,则考虑排序。
-
若问题具备 “求解难, 但是验证解是否可行容易” 结构,则考虑二分答案。
-
若问题具备 “最大最小 or 最小最大 or 结果单调性/二分性” 结构,则考虑二分。
-
若问题具备 “枚举单调性” 结构,则考虑双指针。
-
若问题具备 “大数计算”,则考虑高精度。
-
若问题具备 “数据范围大但涉及范围小”,则考虑离散化。
-
若问题具备 “子问题” 结构,则考虑动态规划。
- 若问题具备 ”从1到n符合某些数位限制的个数”,则考虑数位DP
- 若动态规划问题具备 “棋盘上联通约束” 结构,则考虑状态压缩dp
- 若动态规划问题具备 ”固定长度区间最值“ 结构,则考虑单调队列优化。
- 若动态规划问题具备 ”“ 结构,则考虑斜率优化。
- 若动态规划问题具备 ”“ 结构,则考虑四边形不等式优化。
-
若问题具备 “解空间无限 / 有明显优秀策略“ 结构,考虑贪心。
-
若问题具备 “分块” 结构,则考虑 分块 / 块状链表 / 莫队优化暴力
-
若问题具备 ”区间性质“ 结构,则考虑以下经典做法:
- 特殊地,若该性质是区间 ”选点/分组/覆盖/最大不相交“ 的区间数,则按经典问题处理。
- 否则,若该性质具备 ”区间减法 / 区间消去“ 结构,则考虑前缀和 / 差分 / 树状数组 / 线段树 / 平衡树 / 分块。
- 否则,若该性质具备 ”区间加法 / 区间合并“ 结构,则考虑线段树 / 平衡树
-
若问题具备 “状态迁移最少次数” 结构,则考虑最短路算法。
-
若问题具备 “” 结构,则考虑最小生成树算法。
-
若问题具备 “把图分成两部分” 结构,则考虑二分图算法。
-
若问题具备 “把图变成拓扑图” 结构,则考虑强连通分量算法。
-
若问题具备 “对拓扑图求拓扑序” 结构,则考虑拓扑排序算法。
-
若问题具备 “对图恰好走一遍” 结构,则考虑欧拉路径和回路算法。
-
若问题具备 “差分约束” 结构,则考虑图的差分约束算法。
-
若问题具备 “判环” 结构,则考虑SPFA判环。
-
若问题具备 ”面积并”,则考虑计算几何面积并。
-
若问题具备 “最大公约数和最小公倍数“,则考虑gcd。
-
若问题具备 “进制相关“ 结构,则考虑进制转换。
-
若问题具备 “质数相关“ 结构,则考虑判定质数/分解质因数/质数筛
-
若问题具备 ”约数相关” 结构,则考虑所有约数/求约数个数/求约束之和
-
若问题具备 “欧拉函数相关” 结构,考虑欧拉函数算法
-
若问题具备 “幂相关” 结构,考虑快速幂
-
若问题具备 “”溢出long long但是时间限制不严格“ 结构,考虑龟速乘
-
若问题具备 “矩阵运算相关“ 结构,考虑矩阵计算/矩阵快速幂
-
若问题具备 ”阶乘计算相关“ 结构,考虑阶乘快速计算
-
若问题具备 ”线性同余方程“ 结构,考虑扩展欧几里得
-
若问题具备 “线性方程组相关” 结构,考虑高斯消元
-
若问题具备 “组合数”,考虑求组合数的四种算法
-
若问题具备 “容斥” 结构,考虑容斥计算
-
若问题具备 “博弈论” 结构,考虑博弈论
当然这只是冰山一角,真正的细节还有很多。熟练的Coding是刻意练习的结果。
(另外,算法可以有效防止老年痴呆)