算法篇:从思想到题型实践

先建立算法学习路线,覆盖复杂度、递归、二分、双指针、滑动窗口、排序、回溯、字符串、动态规划、贪心与图算法。

已发布文章计算机基础入门8 分钟阅读发布于 2026年9月1日更新于 2026年9月15日
文章目录
  1. 我后来补上的前置基础
  2. 第一组:边界移动类算法
  3. 二分查找
  4. 双指针
  5. 滑动窗口
  6. 第二组:预处理与差量维护
  7. 前缀和
  8. 差分数组
  9. 第三组:排序与分治
  10. 第四组:搜索与回溯
  11. 第五组:字符串算法
  12. 第六组:动态规划
  13. 第七组:贪心
  14. 第八组:图算法
  15. 第九组:工程算法与海量数据
  16. 算法篇的学习顺序
  17. 我后来这样检查自己是否真的理解
知识目录数据结构与算法:从基础到工程实践5 / 77
LOCAL NOTE高亮并记笔记
0 / 1000 · 只保存在这台设备
READER NOTES算法篇:从思想到题型实践》的本机笔记

我最开始接触“算法篇:从思想到题型实践”时,先遇到的是这个问题:我把二分、回溯、动态规划分别背成了几套模板,题目稍微换一种问法就不知道该套哪一个。我没有继续硬记结论,而是把过程画出来,再用一两个最小例子亲手跑通。这篇留下的,就是那次重新梳理后真正帮我想明白的东西。

算法从基础结构、题型练习到工程迁移的路线

算法篇解决的问题是:面对一个具体任务,应该用什么步骤,在可接受的时间和空间内得到正确答案。

如果数据结构是“状态如何组织”,算法就是“状态如何变化”。很多算法看起来像模板,其实背后都有共同的思维:缩小搜索范围、复用历史结果、维护单调性、拆分问题、剪枝无效路径、选择局部最优、在图上扩散状态。

这一篇先作为算法篇总览,不急着写完所有细节。后续每个方向会拆成独立文章,配图、代码、复杂度、场景和面试题。

我后来补上的前置基础

算法不是从动态规划开始的,也不是从刷题数量开始的。

更稳的前置基础是:

  1. 会分析时间复杂度和空间复杂度。
  2. 理解递归调用栈。
  3. 熟悉数组、链表、栈、队列、哈希表、树、图这些基础结构。
  4. 能写清楚边界条件。
  5. 能用测试样例证明自己的理解。

很多算法题做不出来,不是因为缺一个神奇模板,而是因为没有先把状态、边界和数据结构关系想清楚。

第一组:边界移动类算法

这一组最常出现在数组和字符串里。

二分查找

二分的本质不是“在有序数组里找数”这么窄,而是不断缩小答案区间。

常见类型:

  • 查找某个目标值。
  • 查找左边界或右边界。
  • 查找第一个满足条件的位置。
  • 答案二分,例如最小可行速度、最大可行容量。

二分最容易错在:

  • 区间定义不清楚。
  • leftright 更新后没有收敛。
  • mid 计算溢出。
  • 返回值到底是 left 还是 right 没想明白。

双指针

双指针用两个位置描述当前处理范围。

常见类型:

  • 相向双指针:两数之和、反转数组、回文判断。
  • 同向双指针:原地去重、快慢指针。
  • 快慢指针:链表环检测、找中点。

双指针的关键不是指针数量,而是每次移动哪个指针,以及为什么不会漏答案。

滑动窗口

滑动窗口是双指针的一种常见形式,用于维护一个连续区间。

典型问题:

  • 最长无重复子串。
  • 最小覆盖子串。
  • 固定长度窗口最大值。
  • 满足某个条件的最长/最短区间。

滑动窗口最重要的是两个判断:

什么时候扩大窗口?
什么时候收缩窗口?

如果这两个条件没写清楚,代码看起来像模板,实际很容易错。

第二组:预处理与差量维护

前缀和

前缀和把重复区间求和变成一次预处理和 O(1) 查询。

核心公式:

sum(l, r) = prefix[r + 1] - prefix[l]

它适合频繁查询区间和,但不适合频繁单点修改或区间修改。

差分数组

差分数组把区间修改变成两个端点变化。

对区间 [l, r]delta

diff[l] += delta
diff[r + 1] -= delta

最后再通过前缀和还原数组。

它适合“多次区间修改,最后统一查询结果”的场景。

第三组:排序与分治

排序不是为了背十几个算法,而是理解比较、交换、分区、合并和稳定性。

需要掌握:

  • 冒泡、选择、插入:用于理解基础交换和局部有序。
  • 快速排序:理解分区、随机化和最坏情况。
  • 归并排序:理解分治、合并和稳定性。
  • 堆排序:理解堆不变量和原地排序。
  • 计数、桶、基数排序:理解非比较排序的适用条件。

排序算法要比较:

算法 平均时间 最坏时间 空间 稳定性
插入排序 O(n²) O(n²) O(1) 稳定
快速排序 O(n log n) O(n²) O(log n) 不稳定
归并排序 O(n log n) O(n log n) O(n) 稳定
堆排序 O(n log n) O(n log n) O(1) 不稳定
计数排序 O(n + k) O(n + k) O(k) 可稳定

我的判断是:排序的重点不是“哪个最快”,而是输入规模、数据分布、稳定性、额外空间和工程库实现。

第四组:搜索与回溯

搜索是在状态空间中找答案。

DFS 更适合沿一条路径深入;BFS 更适合按层扩散;回溯则是在 DFS 基础上加入选择、撤销和剪枝。

回溯常见结构:

选择一个候选
进入下一层
如果不合适就回退
撤销选择

典型问题:

  • 子集
  • 组合
  • 排列
  • N 皇后
  • 括号生成
  • 单词搜索
  • 岛屿数量

回溯不是暴力的代名词,它的关键是剪枝。真正好的回溯代码应该能说明:哪些分支没有必要继续走。

第五组:字符串算法

字符串算法现在分成基础和进阶两层:基础先理解暴力匹配、KMP 和哈希;进阶再进入 AC 自动机、Manacher、Z 函数和后缀数组。

需要覆盖:

  • 暴力匹配。
  • Rabin-Karp 与滚动哈希。
  • 字符串哈希和冲突处理。
  • KMP 与前缀函数。
  • Z 函数。
  • Manacher 回文算法。
  • Trie 与 AC 自动机。
  • 后缀数组入门。

字符串算法最容易画错图,所以阅读时要重点观察:

  • 模式串和文本串上下对齐。
  • 失配跳转方向清晰。
  • 前缀、后缀、公共前缀不要混用。
  • 自动机失败指针不能和 Trie 边混在一起。

第六组:动态规划

动态规划不是背公式,而是设计状态。

一篇 DP 文章必须回答:

  1. 状态是什么?
  2. 选择是什么?
  3. 转移从哪里来?
  4. base case 是什么?
  5. 遍历顺序为什么这样?
  6. 是否可以空间压缩?

常见类型:

  • 线性 DP:爬楼梯、打家劫舍、最大子数组。
  • 子序列 DP:LIS、LCS。
  • 背包 DP:0-1 背包、完全背包、多重背包。
  • 区间 DP:合并石子、回文区间。
  • 树形 DP:树上选择和路径状态。
  • 状态压缩 DP:集合状态和位掩码。
  • 编辑距离:插入、删除、替换。

DP 的图解重点应该是状态表填充方向。读者要能看出来每个格子依赖哪些格子,而不是只看到一个公式。

第七组:贪心

贪心的难点不是写代码,而是证明为什么局部选择不会破坏全局最优。

适合贪心的题通常有:

  • 区间调度。
  • 跳跃游戏。
  • 分发糖果。
  • 最少箭射气球。
  • 合并区间。
  • Huffman 编码。

贪心最危险的地方是:样例能过,不代表策略正确。后续写贪心文章时,必须加入反例和证明思路。

第八组:图算法

图算法依赖图结构,但它的重点是求解问题。

需要独立成文:

  • DFS 与 BFS 框架。
  • 拓扑排序与有向图判环。
  • Dijkstra 非负权最短路。
  • Bellman-Ford 与负权边。
  • Floyd 多源最短路。
  • Prim 与 Kruskal 最小生成树。
  • 二分图判断。
  • 强连通分量。
  • 网络流入门。

图算法的第一步永远是建模。边方向、权重含义、重复边、自环、稀疏/稠密程度,都会影响算法选择。

第九组:工程算法与海量数据

算法学到最后,要能回到真实系统里。很多工程问题不是单纯刷题,但背后仍然是数据结构与算法组合。

需要掌握:

  • Top K 海量数据:分桶、哈希统计、小顶堆。
  • 海量去重:Bitmap、Bloom Filter、分治分桶。
  • 外部排序:分块排序、多路归并。
  • 倒排索引:从词找到文档,是搜索系统的核心。
  • 一致性哈希:节点扩缩容时减少数据迁移。
  • LRU:哈希表和双向链表组合维护缓存淘汰。

这一组的重点不是手写多复杂的代码,而是学会问约束:内存够不够、结果是否必须精确、是否需要实时、是否需要排序、能不能接受误判。

算法篇的学习顺序

推荐路线:

复杂度、递归
二分、双指针、滑动窗口
前缀和、差分
排序、分治
搜索、回溯
树算法、图算法
字符串算法
动态规划
贪心、图论进阶
海量数据、倒排索引、工程迁移

这不是唯一顺序,但它比较适合从“理解原理”走向“能做题、能解释、能应用”。

我后来这样检查自己是否真的理解

  1. 二分查找的区间到底是左闭右闭,还是左闭右开?
  2. 双指针为什么移动一个指针不会漏掉答案?
  3. 滑动窗口什么时候扩大,什么时候收缩?
  4. 前缀和适合什么查询,不适合什么修改?
  5. 快速排序为什么平均快,但最坏可能退化?
  6. 回溯为什么要撤销选择?
  7. 动态规划和记忆化搜索是什么关系?
  8. KMP 的 next 数组到底保存什么?
  9. Dijkstra 为什么要求边权非负?
  10. 贪心算法为什么必须证明正确性?
  11. AC 自动机为什么适合多模式匹配?
  12. 海量数据题为什么不能只回答 HashMap?
JARVIS · 当前文章

有哪里没看懂?可以只问这篇。

Jarvis 会限定在《算法篇:从思想到题型实践》及其公开关联内容中检索,并把引用定位回原文章节。

JARVIS / ARTICLE针对《算法篇:从思想到题型实践》提问
当前范围算法篇:从思想到题型实践不会悄悄扩大到全站
0 / 1000

准备好了。当前只会围绕算法篇:从思想到题型实践回答。

READER SIGNAL

这篇内容对你有帮助吗?

不需要登录。你的反馈会直接进入作者待处理列表。