刷题路上最卡人的往往不是代码,而是「这个概念到底是什么、什么时候该用它」。这里每个概念一页讲透: 一句话定义、生活类比、识别信号、和易混概念的区别,配上能看动画的例题。看完概念,再去刷对应题单,事半功倍。
单调栈是栈的一种用法:每个新元素入栈前,先把栈里比它「差」的栈顶依次弹出,让栈从底到顶始终保持单调递增或递减。弹出发生的那一刻,答案就产生了——被弹出的元素刚好遇到了它右边第一个更大(或更小)的数。整个数组每个元素最多进栈一次、出栈一次,O(n) 解决暴力要 O(n²) 的「找最近的更大/更小元素」问题。
读词条 →滑动窗口用左右两个指针围出一段连续区间:右指针不断把新元素纳入窗口,一旦窗口「不合法」(出现重复、和超标……),左指针就向右收缩直到恢复合法。两个指针都只前进、不回退,每个元素最多进窗口一次、出窗口一次,把暴力枚举所有区间的 O(n²) 压到 O(n)。
读词条 →双指针是让两个下标按一定规则在数组或链表上移动的技巧,靠「有序性」或「已处理过的信息」保证每次移动都不会漏掉答案,从而省去一层循环,把 O(n²) 降到 O(n)。常见三种形态:从两端往中间走的对撞指针、一前一后同方向推进的同向指针、一步与两步赛跑的快慢指针。
读词条 →前缀和是把数组「先累加一遍存起来」的预处理技巧:令 pre[i] 表示前 i 个数之和(pre[0]=0),那么任意区间 [l, r] 的和等于 pre[r+1] − pre[l],一次减法 O(1) 出结果,不必每问一次就从头加一遍。搭配哈希表,还能一遍扫完统计「和为 K 的子数组」的个数。
读词条 →并查集(Union-Find)是一种只干两件事的数据结构:把两个集合合并(union)、查询两个元素是否属于同一集合(find)。实现上让每个节点记住自己的父节点,树根就是集合的代表;配合路径压缩和按秩合并,单次操作均摊接近 O(1)。它是处理「连通块 / 朋友圈 / 动态加边判环」类问题的利器。
读词条 →拓扑排序是把有向无环图(DAG)的所有节点排成一个线性顺序,使每条边都从排在前面的节点指向排在后面的节点——「先修课永远排在后修课前面」。标准做法是 Kahn 算法:反复取出入度为 0 的节点放进结果、并给它的后继减入度;如果最后取出的节点数少于总数,说明图中有环,根本不存在合法顺序。
读词条 →动态规划(DP)是解决「大问题由重叠子问题组成」的方法:用一张表把每个子问题的答案记下来,从最小的情况出发,按转移方程一步步推到目标——每个子问题只算一次,查表复用。写一个 DP 只需回答三件事:状态是什么(dp[i] 表示什么)、转移方程怎么写(dp[i] 由哪些更小的状态推出)、边界是什么(最小的几个状态直接给值)。
读词条 →回溯是在「决策树」上做深度优先搜索的枚举框架:每一层从候选集合里做一个选择、递归进入下一层;递归返回时撤销刚才的选择,回到干净的现场再试下一个分支。三步循环——做选择、递归、撤销选择——配合剪枝砍掉注定无解的分支,就能系统地枚举出排列、组合、子集、棋盘摆放等所有候选方案。
读词条 →二分查找的真正难点不是「找到等于 target 的位置」,而是找边界:第一个大于等于 target 的位置(左边界)、最后一个小于等于 target 的位置(右边界)。写对边界的钥匙是把「循环不变量」说出口——答案一定在当前区间里,每轮收缩都必须保住这句话,并且让区间实实在在变小。
读词条 →DFS(深度优先搜索)一条路走到黑、走不通再回头换路,靠递归或显式栈实现;BFS(广度优先搜索)从起点一圈一圈向外扩散,靠队列实现。最关键的分工只有一句:无权图求「最短步数」必须用 BFS——它第一次碰到终点时走过的层数就是最短距离;而枚举所有方案、探索连通块,DFS 写起来更短更顺手。
读词条 →「两数之和为什么用哈希不用排序」「二分查找为什么死循环」——10 个真实困惑,每个一页直接回答。