CalcGuide · 技术博客主页 / 一页纸学习计划
🟠

分治:从归并排序到最近点对

分类:数据结构与算法 · 路径:docs/topics/divide-and-conquer/README.md

#algorithms#divide-conquer#merge-sort#quicksort#recurrence

理解主定理、写分治递推式、用分治解决归并 / 快排 / 最近点对等问题

父主题

算法设计方法:从递归到动态规划

子主题(0)

分治:从归并排序到最近点对

0. 元信息

1. 学习路线

分治范式:分解 → 解决 → 合并
  → 归并排序(含计数逆序对)
  → 快速排序与 partition(Hoare / Lomuto)
  → 主定理(Master Theorem)三种情况
  → 二分查找与二分答案
  → 最近点对(Closest Pair)
  → 大整数乘法 / Strassen
  → 棋盘覆盖 / CDQ 分治

每一步都推 T(n)。归并排序是分治的”教科书级”案例。

2. 阶段周数分配

阶段2 周方案3 周方案备注
1. 归并排序 + 逆序对1 天1.5 天T(n) = 2T(n/2) + O(n)
2. 快速排序 + partition1.5 天2 天Hoare / Lomuto + pivot
3. 主定理三种情况1 天1.5 天log_b(a) vs f(n)
4. 二分查找 + 二分答案1.5 天2 天边界 + 判定函数
5. 最大子数组和(分治)1 天1.5 天Kadane + 分治对照
6. 最近点对1.5 天2 天7 点扫描
7. Strassen / FFT0.5 天1 天O(n^2.81) 推导
8. CDQ 分治0.5 天1.5 天三维偏序

每天 1.5~2 小时。2 周方案聚焦前 5 阶段;3 周方案多一周做最近点对与 Strassen。

3. 九阶段表(精简)

3.1 核心知识

3.2 实践产出

3.3 可观察学会标准

4. 第一周(每天 1.5~2 小时)

Day 1 约定:本计划使用 Python 3.10+。统一格式:python -X dev -W error -m py_compile foo.py;测试用 pytest。所有代码放进 algo-design/divide-conquer/week<N>/ 目录;每个题目单独 .py 文件,配套 notes/<problem>.md 含递推式 T(n) 推导、递归树图、Master Theorem 验证。

任务当天交付自检
Day 1装 Python 3.11 + pytest + ruff;手写 4 道递归基础:阶乘、斐波那契、汉诺塔、pow(x,n);为每道画递归调用栈图week1/day1/recursion.md 含 4 张调用栈图pytest week1/day1/test_recursion.py 4 passed;python -c "import sys; sys.setrecursionlimit(200000); print(pow(2, 1000))" 跑通
Day 2归并排序 + 计数逆序对:写 merge_sortcount_inversions;画递归树标出 T(n) = 2T(n/2) + O(n)week1/day2/merge_sort.py + 逆序对测试pytest week1/day2/test_merge.py 4 passed(n=0, 1, 10, 1000);逆序对数与 O(n²) 暴力解一致
Day 3快速排序 + partition:实现 Hoare 与 Lomuto 两种 partition;用随机 pivot + 三数取中;测试已排序数组不退化week1/day3/quick_sort.pypytest week1/day3/test_quick.py 5 passed(含已排序 1000 元素);Hoare vs Lomuto 对比耗时表
Day 4主定理三种情况:写 6 道递推式(2T(n/2)+O(n) / 2T(n/2)+O(1) / 4T(n/2)+O(n²) / 2T(n/2)+O(n²) / T(n/2)+O(1) / 4T(n/2)+O(n)),用 Master Theorem 解 T(n)week1/day4/master.py + 6 道递推式求解pytest week1/day4/test_master.py 6 passed;每道递推式写出 log_b(a)f(n) 的比较
Day 5二分查找 + 二分答案:写 bisect_left / bisect_right;写 LeetCode 34 在排序数组中找元素范围;写一道二分答案题(LeetCode 410 分割数组的最大值)week1/day5/binary_search.pypytest week1/day5/test_binary.py 3 passed;LeetCode 3/3 AC;记录 left < right vs left <= right 边界
Day 6最大子数组和(Kadane + 分治):先写 Kadane O(n),再写分治 O(n log n);对照结果week1/day6/max_subarray.pypytest week1/day6/test_subarray.py 4 passed(n=0, 1, 10, 1000);Kadane 与分治结果一致;分治 T(n) = 2T(n/2) + O(n)
Day 7步骤 A:完成归并排序的完整推导(递推式 + 递归树 + Master Theorem + 实际耗时曲线);步骤 B:补齐 4 类边界(n=0 空 / n=1 单元素 / 已排序 / 全逆序)week1/day7/merge.py + 4 类边界日志pytest -k test_merge 4 个用例全过;每类边界用例的输入/期望/实际写到 notes/week1-day7.md

Day 7 执行次序

步骤 A —— 归并排序完整版(60~90 分钟)

  1. merge_sort(arr)
  2. 写递推式 T(n) = 2T(n/2) + O(n);
  3. 用 Master Theorem 解 T(n) = O(n log n);
  4. 画递归树标每层代价;
  5. 跑 n=10, 100, 1000, 10000 测耗时,画 n-log(n) 曲线。

步骤 B —— 4 类边界用例(30~45 分钟)

#用例期望行为验证命令
B1n=0 空数组返回 []pytest -k test_empty
B2n=1 单元素返回 [x]pytest -k test_single
B3已排序 [1,2,3,4]返回 [1,2,3,4]pytest -k test_sorted
B4全逆序 [4,3,2,1]返回 [1,2,3,4],逆序对=6pytest -k test_reverse

Day 7 当天必完成步骤 A;步骤 B 至少完成 B1、B4。

5. 阶段通用验收(精简)

  1. 不看答案重写归并 / 快排 / 二分 / 逆序对 / 最近点对;
  2. 用自己的话解释 Master Theorem 三种情况;
  3. 画出归并 / 快排的递归树,标出每层代价;
  4. 测试 n=0, 1, 2, 100, 10000 五档;
  5. 至少准备 3 组自定义数据贴出实际输出;
  6. 记录每题时间空间复杂度;
  7. 能修改算法(换 pivot、加随机化、并行化)并解释影响。

6. 最终验收

7. 综合项目

首选:分治算法可视化工具(必做:CLI 输入 + 输出 + 可选 GUI)。
备选:归并 / 快排对比器(输入 n → 跑两种排序 → 输出耗时曲线 + 稳定性 + 空间占用)。
备选:最近点对求解器(输入平面点集 → 输出最近距离 + 可视化 + 7 点扫描动画)。

分治算法可视化工具必做要求:

任何综合项目都必须包含:

  1. 需求说明(含输入输出约定);
  2. 数据结构与算法选择理由(为何用分治、为何选这种 partition);
  3. 核心模块说明(Solver / Recorder / Renderer 三层);
  4. 模块化源码(每题单独文件 + 公共 base class);
  5. 边界测试(n=0, 1, 2, 100, 10000 + 已排序 + 全逆序);
  6. 运行说明(Makefile 或清晰的 python -m 命令);
  7. README(项目介绍、运行步骤、目录结构、复盘);
  8. notes/ 规范
文件内容
notes/design.md数据结构选择理由、递推式 T(n)、Master Theorem 验证
notes/test.md每组测试数据的输入 / 期望输出 / 实际输出 / 通过情况
notes/retrospective.md用时、难点、收获、下一步
notes/recurrence-trees/至少 3 道题(归并 / 快排 / 二分)的递归树图(PNG / DOT 文件)
notes/master-theorem.md6 道递推式的 log_b(a) 与 f(n) 比较表
notes/pivot-comparison.md首元素 / 随机 / 三数取中 三种 pivot 策略的耗时对比表
notes/recursion-traces/关键测试的栈帧表(手画 + 程序输出)
notes/edge-cases.md5 类边界用例的输入 / 期望 / 实际

本主题贡献

3 职责

  1. 把”分解 / 解决 / 合并”形式化为递推式 T(n) = a·T(n/b) + f(n) —— 数清子问题数 a、规模缩小比 b、合并代价 f(n),并对照 Master Theorem 三种情况(f(n) ≪ / ≈ / ≫ n^(log_b a))得到 T(n) 的渐近复杂度。
  2. 区分归并与快排的合并代价 —— 归并排序稳定 O(n log n) 但需 O(n) 辅助空间(非原地),快排原地但最坏 O(n²);pivot 选首元素遇到已排序数组必退化,必须用随机化或三数取中(introsort 思路)。
  3. 把二分查找扩展为二分答案(写”判定函数” → 在单调区间上二分搜索),用分治实现最近点对的 O(n log n) 含跨带 7 点扫描 —— 鸽巢原理保证中线两侧各点只需与对侧固定常数个邻居比较,证明 7 已是最紧的常数。

4 交付物

  1. 14 道题解(归并 / 快排 / 二分 / 计数逆序对 / 最大子数组和 / 最近点对)+ 4 类边界用例日志(n=0 空 / n=1 单元素 / 已排序 / 全逆序)。
  2. 分治可视化工具(CLI → 递推式 T(n) + Master Theorem 解 + 递归树每层代价 + 实际耗时曲线,画归并 / 快排 / 二分 / 最近点对四类)。
  3. Master Theorem 6 道递推式求解表 notes/master-theorem.md2T(n/2)+O(n) / 2T(n/2)+O(1) / 4T(n/2)+O(n²) / 2T(n/2)+O(n²) / T(n/2)+O(1) / 4T(n/2)+O(n),每道标 log_b(a)f(n) 增长阶比较) + 至少 3 题(归并 / 快排 / 二分)的递归树 DOT 文件。
  4. pivot 策略对比表 notes/pivot-comparison.md(首元素 / 随机 / 三数取中在 n=1000 已排序数组上的耗时差距,验证退化防御)。

3 指标

  1. 15 分钟内不看答案重写归并 / 快排(含 Hoare / Lomuto 两种 partition,覆盖分治范式两个最经典的排序实现)。
  2. 在 n=10 / 100 / 1000 / 10000 上画出实际耗时 vs n·log(n) 对比曲线,验证 T(n) = O(n log n)(从实测数据反推理论复杂度,证明”复杂度分析”已可量化)。
  3. 40 分钟内独立实现最近点对的 O(n log n) 含 7 点扫描(鸽巢原理 + 中线 y 排序的工程实现,几何分治的巅峰案例)。
阶段角色资料链接用法
1~2经典书CLRS《Introduction to Algorithms》第 4 版第 4 章https://mitpress.mit.edu/9780262033848/分治与递归精读 4.1~4.5
1~2入门书Manber《Introduction to Algorithms》第 4 章https://www.cs.arizona.edu/~merlin/Algorithms.pdf用归纳讲分治;思维训练
1~2直觉Roughgarden《Algorithms Illuminated》第 2 册https://algorithmsilluminated.org/入门期快速过
1~5范式Skiena《The Algorithm Design Manual》https://www.algorist.com/工程视角 + 题目反查
1~5范式Kleinberg & Tardos《Algorithm Design》第 5 章https://www.cs.princeton.edu/~smattw/与 CLRS 互补
1~3刷题LeetCodehttps://leetcode.cn/中文题库;分治按 tag 刷
1~3刷题CSES Problem Sethttps://cses.fi/分治题集合(Sorting and Searching)
1~3框架labuladong 分治框架https://labuladong.online/algo/中文框架化讲解
1~3图解CP-Algorithms Divide and Conquerhttps://cp-algorithms.com/英文图解 + 代码;当字典
4~5训练USACO Guide 分治模块https://usaco.guide/美国队训练;按难度递进
6几何Preparata & Shamos《Computational Geometry》https://link.springer.com/book/10.1007/978-3-642-96877-1几何分治汇总;选读
6经典Strassen 1969 论文https://link.springer.com/article/10.1007/BF02165411矩阵乘分治上限突破

许可证提示:CLRS 与 Manber 自用学习合理引用;不要复制粘贴 CLRS 课后答案到公开仓库。LeetCode 题面版权见 LeetCode Terms of Service——代码自己写,思路可以分享。CP-Algorithms 是 CC BY-SA。CSES 题面公开。默认做法是读思路后自己重写代码,而不是复制 Editorial。

默认使用顺序:先用 Roughgarden 第 2 册建立分治直觉 → 手写归并 / 快排 + 推 T(n) → 用 Master Theorem 验 → 选读 CLRS 第 4 章 → 用 LeetCode 刷 6 道分治题 → 跑 CSES 排序与搜索章节 → 用 labuladong / CP-Algorithms 对照 5 道卡住的题 → 实现最近点对 → 选读 Strassen 1969 论文 → 写复盘到 notes/retrospective.md

8. 推荐开源资料

阶段角色资料链接用法
1~2经典书CLRS《Introduction to Algorithms》第 4 版第 4 章https://mitpress.mit.edu/9780262033848/分治与递归精读 4.1~4.5
1~2入门书Manber《Introduction to Algorithms》第 4 章https://www.cs.arizona.edu/~merlin/Algorithms.pdf用归纳讲分治;思维训练
1~2直觉Roughgarden《Algorithms Illuminated》第 2 册https://algorithmsilluminated.org/入门期快速过
1~5范式Skiena《The Algorithm Design Manual》https://www.algorist.com/工程视角 + 题目反查
1~5范式Kleinberg & Tardos《Algorithm Design》第 5 章https://www.cs.princeton.edu/~smattw/与 CLRS 互补
1~3刷题LeetCodehttps://leetcode.cn/中文题库;分治按 tag 刷
1~3刷题CSES Problem Sethttps://cses.fi/分治题集合(Sorting and Searching)
1~3框架labuladong 分治框架https://labuladong.online/algo/中文框架化讲解
1~3图解CP-Algorithms Divide and Conquerhttps://cp-algorithms.com/英文图解 + 代码;当字典
4~5训练USACO Guide 分治模块https://usaco.guide/美国队训练;按难度递进
6几何Preparata & Shamos《Computational Geometry》https://link.springer.com/book/10.1007/978-3-642-96877-1几何分治汇总;选读
6经典Strassen 1969 论文https://link.springer.com/article/10.1007/BF02165411矩阵乘分治上限突破

许可证提示:CLRS 与 Manber 自用学习合理引用;不要复制粘贴 CLRS 课后答案到公开仓库。LeetCode 题面版权见 LeetCode Terms of Service——代码自己写,思路可以分享。CP-Algorithms 是 CC BY-SA。CSES 题面公开。默认做法是读思路后自己重写代码,而不是复制 Editorial。

默认使用顺序:先用 Roughgarden 第 2 册建立分治直觉 → 手写归并 / 快排 + 推 T(n) → 用 Master Theorem 验 → 选读 CLRS 第 4 章 → 用 LeetCode 刷 6 道分治题 → 跑 CSES 排序与搜索章节 → 用 labuladong / CP-Algorithms 对照 5 道卡住的题 → 实现最近点对 → 选读 Strassen 1969 论文 → 写复盘到 notes/retrospective.md

9. 学习资料汇聚(v0.3)

9.1 背景与动机

分治思想可追溯到 1840 年代 Gauss 的大数乘法思想;Hoare 在 1959 年发明快速排序,奠定了分治在排序里的核心地位;Strassen 在 1969 年用分治把矩阵乘法从 O(n³) 降到 O(n²·log₂7) ≈ O(n^2.81),这是分治范式最具冲击力的结果。CLRS 把 Master Theorem 形式化成了 4 版教材里的”必学章节”。

行业位置:分治是排序、搜索、FFT、CDQ 分治的基础。算法面试常考”写出归并 / 快排 + 解释复杂度”。竞赛里 FFT / CDQ 是高级选手的工具。一句话总结:分治 = 把问题拆成互不重叠的子问题,最后合并答案。

9.2 概念地图

flowchart LR
  Divide[分解]
  Conquer[解决子问题]
  Combine[合并]
  MergeSort[归并排序]
  QuickSort[快速排序]
  BinarySearch[二分查找]
  InversionCount[计数逆序对]
  ClosestPair[最近点对]
  Strassen[Strassen 矩阵乘]
  Master[主定理]
  Recurrence[递推式]

  Divide --> Conquer --> Combine
  MergeSort --> Divide
  QuickSort --> Divide
  BinarySearch --> Divide
  InversionCount --> MergeSort
  ClosestPair --> Divide
  Strassen --> Divide
  Master --> Recurrence
  Recurrence --> MergeSort
  Recurrence --> QuickSort
  Recurrence --> ClosestPair

核心关系:分治三步是底座;归并 / 快排 / 二分是三个最常见实例;Master Theorem 把复杂度推导形式化;最近点对是分治 + 跨带优化的巅峰案例。

9.3 基础知识讲解

9.3.1 经典论文

资料影响建议读法
Hoare, Quicksort(1962)快速排序算法看 partition 的两种写法
Strassen, Gaussian Elimination is not Optimal(1969)矩阵乘 O(n^2.81)看分治递归式
Cooley & Tukey, An Algorithm for the Machine Calculation of Complex Fourier Series(1965)FFT看分治 + 旋转因子
Bentley, Divide and Conquer Algorithms for Closest Point Problems(1980)最近点对经典看 7 点扫描的来源
Preparata & Shamos Computational Geometry(1985)几何分治汇总当几何算法字典

9.3.2 经典书籍

影响用法
CLRS 第 4 版第 4 章 Divide-and-Conquer范式标准精读 4.1~4.5
Kleinberg & Tardos 第 5 章 Divide and Conquer设计视角与 CLRS 互补
Manber Introduction to Algorithms 第 4 章用归纳讲分治思维训练
Roughgarden Algorithms Illuminated 第 2 册直觉建立入门期快速过

9.3.3 优秀博客

资料特点用法
CP-Algorithms Divide and Conquer英文图解 + 代码当字典
labuladong 分治框架中文框架当 Cheatsheet
USACO Guide 分治模块按难度递进长期刷题路线
CSES Sorting and Searching分治题集合训练用

9.3.4 核心人物

人物主要影响建议追踪的材料
Tony Hoare快速排序、Hoare 逻辑1962 Quicksort 论文
Volker StrassenStrassen 矩阵乘1969 论文
James Cooley / John TukeyFFT1965 论文
Jon Bentley最近点对等几何分治1980 论文
冯·诺依曼1945 年 EDVAC 报告奠定分治与递归基础历史阅读

9.3.5 开发方法

方法具体动作何时用
Recurrence-first先写 T(n) = …,再写代码任何分治题
Master-Theorem-check用 Master Theorem 验证 T(n)排序、搜索
Pivot-randomizationpivot 用随机元素或三数取中快排避免最坏
Mid-band scan把跨带子问题限制到固定常数窗口最近点对
Cache-friendly merge用归并而不是快排处理大文件外部排序

9.4 经典问题与经典案例

#问题为什么重要最简答案或图示
1归并排序分治范式入门T(n) = 2T(n/2) + O(n) = O(n log n)
2快速排序原地分治期望 O(n log n),最坏 O(n²)
3二分查找分治的最简形式T(n) = T(n/2) + O(1) = O(log n)
4计数逆序对归并排序的应用合并时 if a[i] > a[j]: cnt += mid - i + 1
5LeetCode 4 找中位数双数组分治二分第 k 小元素
6LeetCode 23 合并 K 升序链表优先队列 vs 分治分治两两合并 O(n log k)
7最大子数组和(分治版)分治范式练习T(n) = 2T(n/2) + O(n)
8最近点对分治 + 跨带 7 点扫描中线两侧 + y 排序扫描
9Strassen 矩阵乘分治上限突破7 次子乘而非 8 次
10FFT分治 + 旋转因子O(n log n) 计算多项式乘

9.5 学习难点

概念难点

难点为什么会卡突破路径
Master Theorem 三种情况记不清规则用 log_b(a) 与 f(n) 的增长速度比对
归并 vs 快排合并代价算错 f(n)画递归树,标每层节点数 × 合并代价
pivot 选择选首元素 = 已排序时退化用随机化或三数取中
二分边界left < right 还是 left <= right写 n=1, n=2 例子手动调

思维难点

难点为什么会卡突破路径
写递推式子问题数和规模缩小比算不出数”分解成几块”和”每块大小”
跨带扫描最近点对的 7 点证明看不懂画中线两侧 + 距离 d;用鸽巢原理
二分答案把问题归约到判定先写出”判定函数”,再二分答案
CDQ 分治三维偏序不容易上手先做二位逆序对,再加第三维

工程难点

难点为什么会卡突破路径
Python 递归深度归并递归深度 = log n 通常没事,但快排可能 O(n)用迭代版本快排;或 setrecursionlimit
归并排序空间 O(n)大数组内存紧张用原地归并(复杂度上升)或换快排
快排退化已排序 + 选首 pivot = O(n²)用随机 pivot 或 introsort
浮点精度最近点对有精度问题用平方距离比;EPS = 1e-9

9.6 技术标准与接口

9.6.1 Entity

名称版本 / 文档发布组织状态许可证 / 可访问性
CLRS 第 4 版2022MIT Press主流教材第三方 PDF 公开
Python bisectCPython 3.10+PSF内建PSF License
functools.lru_cacheCPython 3.10+PSF内建PSF License
CSES Problem Set持续更新CSES公开公开题面

9.6.2 Scope

9.6.3 Structure

9.6.4 Ecosystem

9.6.5 Depth Tiers

层级能力分治的可观察标准
L0知道存在知道归并 / 快排 / 二分 / 最近点对都是分治
L1看得懂示例能读懂别人的分治代码
L2能正确调用能写归并 / 快排 / 二分
L3能解释与排错能推导 T(n),能解释快排退化与最近点对的 7 点
L4能设计与扩展能设计新的分治算法(如 Strassen 类)

本子主题目标:L3。能写归并 / 快排 + 推导 T(n) + 实现最近点对即达到。

9.6.6 Source

10. 常见误区


11. 所有知识点分类

  1. 编程语言(辅):Python 列表切片与拷贝、bisect.bisect_left / bisect_right 做二分、heapq.merge 做多路归并、functools.lru_cache 做递归 memo、递归迭代化与 sys.setrecursionlimit
  2. 数据结构与算法(主):分治三步(分解 / 解决 / 合并)、递推式 T(n) = a·T(n/b) + f(n)、Master Theorem 三种情况、归并排序(含计数逆序对)、快速排序(Hoare / Lomuto partition、pivot 随机化)、二分查找(递归 / 迭代 / 二分答案)、最近点对(分治 + 跨带 7 点扫描)、Strassen 矩阵乘、FFT、CDQ 分治。
  3. 计算机基础:递归与递推式、Master Theorem 形式化证明、鸽巢原理(最近点对 7 点来源)、浮点精度与 EPS。
  4. 工程技术:画递归树并标每层代价、pivot 策略对比(首元素 / 随机 / 三数取中)、外部排序的 cache-friendly 合并、n × 2^n 状态数估算与算法选型。
  5. Web 与后端:无直接关联。
  6. 前端与客户端:无直接关联。
  7. 数据与人工智能:FFT 可作为信号处理基础;本计划不展开。
  8. 项目与职业能力:LeetCode 4 / 23 / 315 / 327 等分治面试题、15 分钟重写归并 / 快排、40 分钟实现最近点对 O(n log n)。

本计划归属:数据结构与算法 主 + 编程语言 辅。


直接依赖(1)

查看知识图谱