TL;DR
- 分治范式与递推:分治法三步曲(划分、递归求解、合并),通过主定理精确界定递归树深度与各层工作量的平衡关系。
- 确定性线性选择(BFPRT):通过“五分中位数”(Median of Medians)选定主元,确保每次递归至少剪除 3/10 的搜索空间,实现 T(n)≤T(n/5)+T(7n/10)+O(n)=O(n) 的严格最坏线性时间。
- Karatsuba 大整数乘法:巧妙利用一次代数恒等变形将 4 次半长整数乘法降为 3 次,将经典多项式乘法复杂度由 O(n2) 打破至 O(nlog23)≈O(n1.585)。
- 凸包分治构造:平面点集按横坐标二分,递归求得左右凸包后,通过双指针双向旋转在 O(n) 时间内找到公切线合并,达到与基于排序下界匹配的 O(nlogn) 复杂度。
分治法核心范式与主定理
分治(Divide and Conquer)是算法设计中最基础且强大的思维范式之一,标准执行流程包含三个阶段:
- 分解(Divide):将原问题划分为若干规模较小但结构相同的子问题;
- 解决(Conquer):递归求解各个子问题。当子问题足够小时直接求解(递归基);
- 合并(Combine):将各个子问题的解答合并为原问题的完整解。
主定理(Master Theorem)
对于形如 T(n)=aT(n/b)+f(n) 的递归式(其中 a≥1,b>1 为常数),设临界指数为 logba:
- 情况 1(叶节点支配):若存在 ϵ>0 使得 f(n)=O(nlogba−ϵ),则 T(n)=Θ(nlogba);
- 情况 2(各层均衡):若 f(n)=Θ(nlogbalogkn)(k≥0),则 T(n)=Θ(nlogbalogk+1n);
- 情况 3(根节点支配):若存在 ϵ>0 使得 f(n)=Ω(nlogba+ϵ) 且满足正则性条件,则 T(n)=Θ(f(n))。
中位数与顺序统计量:确定性线性时间选择(BFPRT)
问题定义
定义
顺序统计量(Order Statistic)
给定包含 n 个互异元素的集合 S 与整数 i∈{1,2,…,n},求 S 中第 i 小的元素(即秩 rank(x)=i 的元素)。
当 i=⌊(n+1)/2⌋ 时,该元素即为中位数(Median)。
若先对全量元素排序再按索引访问,时间复杂度为 O(nlogn)。若采用快速选择算法(QuickSelect),通过随机选取主元(Pivot)期望可在 O(n) 内完成,但最坏情况下仍可能退化至 O(n2)。
能否在最坏情况下依然保证 O(n) 确定性时间?Blum、Floyd、Pratt、Rivest 与 Tarjan 在 1973 年给出了划时代的 BFPRT 算法。
算法步骤与五分中位数策略
为了防止快速排序划分时出现极端倾斜,算法必须确定性地构造出一个“足够居中”的主元 x:
- 分组:将 n 个元素划分为 ⌊n/5⌋ 个大小为 5 的子组,若有剩余(nmod5 个元素),单独作为一组;
- 求组内中位数:对每个大小为 5 的子组进行排序(每组至多 7 次比较,耗时 O(1)),取出每组的中位数,共得到 ⌈n/5⌉ 个中位数;
- 递归求中位数的中位数:递归调用选择算法,找出这 ⌈n/5⌉ 个组内中位数的中位数,记为主元 x;
- 主元划分:以 x 为基准将原集合划分为三个集合:
- L={y∈S∣y<x}
- E={y∈S∣y=x}
- G={y∈S∣y>x}
- 递归分支收敛:
- 若 i≤∣L∣,则在 L 中递归寻找第 i 小元素;
- 若 ∣L∣<i≤∣L∣+∣E∣,直接返回 x;
- 若 i>∣L∣+∣E∣,则在 G 中递归寻找第 i−∣L∣−∣E∣ 小元素。
空间剪枝与复杂度推导
定理
BFPRT 主元平衡界
由 BFPRT 算法选出的主元 x,至少大于原数组中的 3n/10−6 个元素,且至少小于原数组中的 3n/10−6 个元素。
证明:
考虑步骤 2 中获得的全部组内中位数。在这 ⌈n/5⌉ 个中位数中,至少有一半(即 21⌈n/5⌉≥10n 个)小于等于 x。
在每一个中位数小于等于 x 的 5 元组中,除了该组中位数自身之外,还有 2 个元素小于等于该中位数,因而至少有 3 个元素小于等于 x。
排除掉主元自身所在组以及可能不足 5 个元素的剩余组,严格小于等于 x 的元素数量至少为:
3(⌈21⌈5n⌉⌉−2)≥3(10n−2)=103n−6
同理,严格大于等于 x 的元素数量也至少为 3n/10−6。
由此可得,在最坏情况下,进入步骤 5 递归的子问题规模上限为:
max(∣L∣,∣G∣)≤n−(103n−6)=107n+6
递归式求解:为什么必须是 5?
整体算法的运行时间递归关系为:
T(n)≤T(⌈5n⌉)+T(107n+6)+O(n)
我们使用代入法证明 T(n)≤cn。设常数项满足 O(n)≤c0n:
T(n)≤c(5n+1)+c(107n+6)+c0n=c(109n+7)+c0n=cn−(10cn−7c−c0n)
只要取足够大的常数 c(例如当 n≥140 时),括号内项恒为正,即可保证 T(n)≤cn=O(n)。
我的理解
思考:为什么不用 3 分组?
若将元素按 3 个一组划分,主元递归项为 T(n/3),剩余递归项至多包含 n−2(n/6)=2n/3 个元素。此时递推式为:
T(n)=T(n/3)+T(2n/3)+O(n)由于 1/3+2/3=1,递归树每一层的总代价均为 O(n),树深为 O(logn),整体复杂度退化为 O(nlogn)!
因此,5 是保证子问题规模系数和严格小于 1(1/5+7/10=9/10<1)的最小奇数。
大整数乘法:Karatsuba 算法
给定两个各包含 n 位的大整数 A 与 B,计算乘积 A×B。经典逐位相乘算法需要 O(n2) 次位运算。
将两数按二进制高低位拆半:
A=2n/2X+Y,B=2n/2W+Z
展开式包含 4 个规模为 n/2 的子乘法:
A×B=2n(XW)+2n/2(XZ+YW)+(YZ)
若直接递归,递推关系为 T(n)=4T(n/2)+O(n)。由主定理,nlog24=n2,并未改善复杂度。
巧妙的恒等式变换
1962 年,苏联数学家 Anatoli Karatsuba 发现交叉项可以通过一次乘法与减法复用求得:
XZ+YW=(X+Y)(W+Z)−XW−YZ
因此,只需递归计算 3 次半长乘法:
- P1=XW
- P2=YZ
- P3=(X+Y)(W+Z)
交叉项即为 P3−P1−P2。
递归式转变为:
T(n)=3T(n/2)+O(n)
应用主定理,临界指数为 log23≈1.585。因此:
T(n)=Θ(nlog23)≈Θ(n1.585)
这一跨越标志着代数复杂度突破二次瓶颈的里程碑,并进一步启发了基于 FFT 的 Schönhage-Strassen 算法。
计算几何:二维凸包的分治构造
定义
凸包(Convex Hull)
给定平面点集 P,包含 P 中所有点的最小凸多边形称为 P 的凸包,记为 CH(P)。
分治法求解步骤
- 预排序:将全部点按 x 坐标递增排序(若 x 相同则按 y 坐标递增),耗时 O(nlogn);
- 二分划分:取中位数垂线,将点集平分为左半部分 A 与右半部分 B;
- 递归求解:分别递归求出 CH(A) 与 CH(B);
- 公切线合并:在 O(n) 时间内寻找连接两凸包的上公切线与下公切线,并删除被切线包围的内部点链。
双指针寻找公切线
以求上公切线为例:
- 分别从 A 中最右侧的点 u 与 B 中最左侧的点 v 开始,连接线段 (u,v);
- 检查线段 (u,v) 是否位于凸包上方:
- 若 A 中存在点位于有向线段 (u,v) 上方,将 u 沿 A 的逆时针方向移动一步;
- 若 B 中存在点位于有向线段 (u,v) 上方,将 v 沿 B 的顺时针方向移动一步;
- 重复上述交替检查与单调旋转,直到线段 (u,v) 完全悬空在两凸包之上。
由于凸多边形的凸性,每个顶点在旋转过程中至多被访问常数次,寻找公切线的时间为 O(∣A∣+∣B∣)=O(n)。
渐近复杂度
合并步骤仅需线性时间,故递归式为:
T(n)=2T(n/2)+O(n)=O(nlogn)
由于平面凸包问题可通过反向归约将数值排序嵌入其中(xi↦(xi,xi2)),在基于比较的模型下,凸包计算的复杂度下界为 Ω(nlogn),因此分治算法达到理论最优渐近界。
我的理解
分治算法不仅是“拆分子问题递归”,其精髓在于重塑合并与剪枝的代数结构:
- 主定理指导下的几何平衡:BFPRT 算法告诉我们,只要能以线性代价确定性地丢弃常数比例(哪怕只是 3/10)的候选集,几何级数衰减就会以 1/(1−c) 的形式将整体复杂度锁定在线性。
- 乘法与加法的代价置换:Karatsuba 的伟大之处在于洞察了加法与乘法计算成本的异构性——位加法是 O(n),而位乘法是 O(n2)。牺牲两次廉价的线性加法来削减一次昂贵的二次乘法,使得分治树的分支因子从 4 降至 3。
- 几何拓扑的单调性支撑:凸包合并之所以能在线性时间内收敛,核心在于凸性的“极角单调性”。分治保证了左右点集在空间上的天然分离,公切线查找如同滑动双指针,将原本难以处理的全局凸包更新降维至局部邻域的切线逼近。
:::