当前位置: 首页 > news >正文

【计算机算法设计与分析】分治算法

文章目录

    • 一、分治核心算法:把大麻烦拆成小麻烦
      • 1. 二分查找:在有序列表里“猜数字”
      • 2. 最大子数组:找股票最赚钱的买卖时机
      • 3. 最近点对:找平面上离得最近的两个点
    • 二、分治复杂度分析:算法到底有多快?
      • 1. 替换法:先猜后验证
      • 2. 序列求和法:把递归“展开”看
      • 3. 主方法:分治的“快捷公式”

一、分治核心算法:把大麻烦拆成小麻烦

分治,顾名思义就是“分而治之”。想象你要拼一幅1000片的拼图,如果直接上手,肯定头晕眼花。但如果把它先分成10个100片的小区域,每个区域再分成更小的部分,拼起来就轻松多了。分治算法就是这个思路,核心是 “分解-求解-合并” 三步:

  1. 分解:把一个大问题拆成几个结构相同、规模更小的子问题;
  2. 求解:对子问题递归求解(如果子问题还大,就继续拆,直到小到能直接解决);
  3. 合并:把所有子问题的解合并成原问题的解。

 

1. 二分查找:在有序列表里“猜数字”

场景:在一本按字母排序的字典里找“Algorithm”这个词,总不能从第一页翻到最后吧?

步骤

  • 分解:看字典中间页,如果中间页的单词比“Algorithm”大,就只看前半本;如果小,就只看后半本。
  • 求解:每次都把范围缩小一半,直到找到目标词或者确定没有。
  • 合并:因为每次只找一半,不需要合并,找到就直接结束。

效果:如果有 n n n 个元素,最多找 log ⁡ 2 n \log_2 n log2n 次(比如1000个数,最多找10次),比从第一个开始挨个找快得多。其时间复杂度可通过递推关系 T ( n ) = T ( n / 2 ) + O ( 1 ) T(n)=T(n/2)+O(1) T(n)=T(n/2)+O(1),结合主方法得 T ( n ) = Θ ( lg ⁡ n ) T(n)=\Theta(\lg n) T(n)=Θ(lgn)

 

2. 最大子数组:找股票最赚钱的买卖时机

场景:你有一段时间每天的股票价格,想找一天买、一天卖,赚最多的钱(如果一直跌,就尽量少亏)。

步骤

  • 分解:把这段时间的价格数组 A [ l o w . . h i g h ] A[low..high] A[low..high] 分成前半段 A [ l o w . . m i d ] A[low..mid] A[low..mid] 和后半段 A [ m i d + 1.. h i g h ] A[mid+1..high] A[mid+1..high]
  • 求解:分别递归找前半段、后半段里最赚钱的买卖时机(即最大子数组和)。
  • 合并:还要检查“前半段的某天买,后半段的某天卖”这种跨段情况——通过从中间向左遍历找最大左和,向右遍历找最大右和,两者相加得到跨段最大和,最终取三者中的最大值。

 

效果
如果直接遍历所有可能的买卖组合,要算 n 2 n^2 n2 次( n n n 是天数);用分治,递推关系为 T ( n ) = 2 T ( n / 2 ) + O ( n ) T(n)=2T(n/2)+O(n) T(n)=2T(n/2)+O(n),结合主方法得 T ( n ) = Θ ( n lg ⁡ n ) T(n)=\Theta(n\lg n) T(n)=Θ(nlgn),数据量大时效率大幅提升。

todo:另外:还有线性时间解法( Θ ( n ) \Theta(n) Θ(n)),通过累计和(SUM)和历史最大和(Bsum)动态更新,进一步简化计算。

 

3. 最近点对:找平面上离得最近的两个点

场景:在一张地图上有很多城市,想找距离最近的两个,方便建高铁。

步骤

  • 分解:把平面上的点集按横坐标排序后,取中点分成左边 L L L 和右边 R R R 两部分。
  • 求解:分别递归找 L L L R R R 中距离最近的点对,设其距离分别为 δ L \delta_L δL δ R \delta_R δR,令 δ = min ⁡ ( δ L , δ R ) \delta=\min(\delta_L,\delta_R) δ=min(δL,δR)
  • 合并:仅需检查分界点左右 δ \delta δ 范围内的点(带状区域),将这些点按纵坐标排序后,每个点只需与后续7个点比较(因 δ × 2 δ \delta \times 2\delta δ×2δ 矩形内最多8个点,避免重复比较),找到跨越区域的最小距离 δ c \delta_c δc,最终结果为
    min ⁡ ( δ , δ c ) \min(\delta,\delta_c) min(δ,δc)

效果:直接对比所有点对要算 n 2 n^2 n2 次( n n n 是点数);用分治,递推关系为 T ( n ) = 2 T ( n / 2 ) + O ( n ) T(n)=2T(n/2)+O(n) T(n)=2T(n/2)+O(n),结合主方法得 T ( n ) = Θ ( n lg ⁡ n ) T(n)=\Theta(n\lg n) T(n)=Θ(nlgn),效率显著优化。

 

二、分治复杂度分析:算法到底有多快?

知道算法怎么用还不够,得知道它“跑得多快”。分治算法的复杂度分析,就是研究“拆问题、解问题、合并问题”这三步加起来,计算机要花多少时间。

1. 替换法:先猜后验证

就像猜谜语,先猜一个答案,再用数学归纳法验证对不对。

例子:针对递推式 T ( n ) = 2 T ( ⌊ n / 2 ⌋ ) + n T(n) = 2T(\lfloor n/2 \rfloor) + n T(n)=2T(⌊n/2⌋)+n(比如最大子数组问题),我们猜它的复杂度是 T ( n ) = Θ ( n lg ⁡ n ) T(n) = \Theta(n\lg n) T(n)=Θ(nlgn)

  • 验证上界:假设存在常数 c > 1 c>1 c>1,当 n ≥ 4 n \geq 4 n4 时, T ( n ) ≤ c n lg ⁡ n T(n) \leq cn\lg n T(n)cnlgn。由归纳假设, T ( ⌊ n / 2 ⌋ ) ≤ c ( n / 2 ) lg ⁡ ( n / 2 ) T(\lfloor n/2 \rfloor) \leq c(n/2)\lg(n/2) T(⌊n/2⌋)c(n/2)lg(n/2),代入递推式得:
    T ( n ) ≤ 2 × c ( n / 2 ) ( lg ⁡ n − 1 ) + n = c n lg ⁡ n − c n + n ≤ c n lg ⁡ n T(n) \leq 2 \times c(n/2)(\lg n - 1) + n = cn\lg n - cn + n \leq cn\lg n T(n)2×c(n/2)(lgn1)+n=cnlgncn+ncnlgn
  • 验证下界:类似地,假设存在常数 0 < d < 1 / 4 0<d<1/4 0<d<1/4,可证明 T ( n ) ≥ d n lg ⁡ n T(n) \geq dn\lg n T(n)dnlgn,最终确定 T ( n ) = Θ ( n lg ⁡ n ) T(n) = \Theta(n\lg n) T(n)=Θ(nlgn)

 

2. 序列求和法:把递归“展开”看

把递推式一层一层展开,像剥洋葱一样,最后把所有步骤的时间加起来,也可通过“递归树”直观呈现各层代价(树的所有节点代价之和即为总复杂度)。

例子:针对递推式 T ( n ) = 2 T ( n / 2 ) + n lg ⁡ n T(n)=2T(n/2)+n\lg n T(n)=2T(n/2)+nlgn T ( 1 ) = O ( 1 ) T(1)=O(1) T(1)=O(1)):

  • n = 2 k n=2^k n=2k,转化为 W ( k ) = 2 W ( k − 1 ) + k 2 k W(k)=2W(k-1)+k2^k W(k)=2W(k1)+k2k
  • 逐层展开: W ( k ) = 2 k W ( 1 ) + 2 k ∑ i = 2 k i W(k) = 2^k W(1) + 2^k \sum_{i=2}^k i W(k)=2kW(1)+2ki=2ki
  • 化简求和项(调和级数或等差数列求和),最终得 T ( n ) = Θ ( n lg ⁡ 2 n ) T(n)=\Theta(n\lg^2 n) T(n)=Θ(nlg2n)

详细解法:

步骤1: 变量替换,简化递归形式 由于原递推式中存在 n / 2 n/2 n/2 lg ⁡ n \lg n lgn,直接展开容易出现复杂的分数和对数项,因此先通过变量替换统一形式:

  • n = 2 k n = 2^k n=2k k k k 为非负整数,确保每次拆分后子问题规模为整数,例如 n = 8 n=8 n=8 k = 3 k=3 k=3 n = 16 n=16 n=16 k = 4 k=4 k=4);
  • 定义新函数 W ( k ) = T ( 2 k ) W(k) = T(2^k) W(k)=T(2k)(将原函数 T T T n n n 的依赖,转化为 W W W k k k 的依赖,消除 n n n 这个中间变量)。
     

步骤2: 代入原递推式,转化为关于 W ( k ) W(k) W(k) 的递归式 将 n = 2 k n=2^k n=2k W ( k ) = T ( 2 k ) W(k)=T(2^k) W(k)=T(2k) 代入原递推式 T ( n ) = 2 T ( n / 2 ) + n lg ⁡ n T(n) = 2T(n/2) + n\lg n T(n)=2T(n/2)+nlgn,分步替换左右两边:

  1. 左边替换 T ( n ) = T ( 2 k ) = W ( k ) T(n) = T(2^k) = W(k) T(n)=T(2k)=W(k)
  2. 右边第一项替换( T ( n / 2 ) T(n/2) T(n/2): 因为 n = 2 k n=2^k n=2k,所以 n / 2 = 2 k / 2 = 2 k − 1 n/2 = 2^k / 2 = 2^{k-1} n/2=2k/2=2k1,因此: T ( n / 2 ) = T ( 2 k − 1 ) = W ( k − 1 ) T(n/2) = T(2^{k-1}) = W(k-1) T(n/2)=T(2k1)=W(k1)
  3. 右边第二项替换( n lg ⁡ n n\lg n nlgn: 先替换 n = 2 k n=2^k n=2k,再利用对数运算规则 lg ⁡ ( 2 k ) = k \lg(2^k) = k lg(2k)=k(以 2 为底的对数,真数为底数的幂时,结果等于指数),因此: n lg ⁡ n = 2 k ⋅ lg ⁡ ( 2 k ) = 2 k ⋅ k = k ⋅ 2 k n\lg n = 2^k \cdot \lg(2^k) = 2^k \cdot k = k \cdot 2^k nlgn=2klg(2k)=2kk=k2k
  4. 合并右边:将两项替换结果代入,得到: 右边 = 2 ⋅ W ( k − 1 ) + k ⋅ 2 k 2 \cdot W(k-1) + k \cdot 2^k 2W(k1)+k2k

最终,原递推式转化为: W ( k ) = 2 W ( k − 1 ) + k ⋅ 2 k W(k) = 2W(k-1) + k \cdot 2^k W(k)=2W(k1)+k2k

 
步骤3: 逐层展开 W ( k ) W(k) W(k),归纳通用规律 采用“序列求和法”,将 W ( k ) W(k) W(k) 逐层展开,直到递归终止(即 W ( 1 ) W(1) W(1),对应原问题的最小规模 n = 2 1 = 2 n=2^1=2 n=21=2):

  1. 第1层(初始) W ( k ) = 2 W ( k − 1 ) + k ⋅ 2 k W(k) = 2W(k-1) + k \cdot 2^k W(k)=2W(k1)+k2k

  2. 第2层(展开 W ( k − 1 ) W(k-1) W(k1): 由 W ( k − 1 ) = 2 W ( k − 2 ) + ( k − 1 ) ⋅ 2 k − 1 W(k-1) = 2W(k-2) + (k-1) \cdot 2^{k-1} W(k1)=2W(k2)+(k1)2k1,代入上式: W ( k ) = 2 [ 2 W ( k − 2 ) + ( k − 1 ) ⋅ 2 k − 1 ] + k ⋅ 2 k = 2 2 W ( k − 2 ) + ( k − 1 ) ⋅ 2 k + k ⋅ 2 k W(k) = 2\left[2W(k-2) + (k-1) \cdot 2^{k-1}\right] + k \cdot 2^k = 2^2 W(k-2) + (k-1) \cdot 2^k + k \cdot 2^k W(k)=2[2W(k2)+(k1)2k1]+k2k=22W(k2)+(k1)2k+k2k

  3. 第3层(展开 W ( k − 2 ) W(k-2) W(k2): 同理, W ( k − 2 ) = 2 W ( k − 3 ) + ( k − 2 ) ⋅ 2 k − 2 W(k-2) = 2W(k-3) + (k-2) \cdot 2^{k-2} W(k2)=2W(k3)+(k2)2k2,代入得: W ( k ) = 2 3 W ( k − 3 ) + ( k − 2 ) ⋅ 2 k + ( k − 1 ) ⋅ 2 k + k ⋅ 2 k W(k) = 2^3 W(k-3) + (k-2) \cdot 2^k + (k-1) \cdot 2^k + k \cdot 2^k W(k)=23W(k3)+(k2)2k+(k1)2k+k2k

  4. 归纳通用形式:展开 m m m 层后,可总结为: W ( k ) = 2 m W ( k − m ) + 2 k ⋅ ∑ i = k − m + 1 k i W(k) = 2^m W(k-m) + 2^k \cdot \sum_{i=k-m+1}^k i W(k)=2mW(km)+2ki=km+1ki

 
步骤4:确定递归终止条件,简化展开式 当递归终止时,子问题规模达到最小,即 k − m = 1 k-m=1 km=1(此时 W ( k − m ) = W ( 1 ) W(k-m)=W(1) W(km)=W(1),对应原问题 T ( 2 ) = O ( 1 ) T(2)=O(1) T(2)=O(1)),因此 m = k − 1 m=k-1 m=k1。将 m = k − 1 m=k-1 m=k1 代入通用形式:
W ( k ) = 2 k − 1 W ( 1 ) + 2 k ⋅ ∑ i = 2 k i W(k) =2^{k-1} W(1) + 2^k \cdot \sum_{i=2}^k i W(k)=2k1W(1)+2ki=2ki

其中:

  • 2 k − 1 W ( 1 ) 2^{k-1} W(1) 2k1W(1):最小子问题的总代价,因 W ( 1 ) = O ( 1 ) W(1)=O(1) W(1)=O(1),该项为 O ( 2 k ) O(2^k) O(2k)(常数乘以指数项);
  • 2 k ⋅ ∑ i = 2 k i 2^k \cdot \sum_{i=2}^k i 2ki=2ki:所有中间合并步骤的总代价,核心是化简求和项 ∑ i = 2 k i \sum_{i=2}^k i i=2ki

 
步骤5:化简求和项,计算 W ( k ) W(k) W(k) 的复杂度 求和项 ∑ i = 2 k i \sum_{i=2}^k i i=2ki 是从 2 到 k k k 的等差数列,利用等差数列求和公式: ∑ i = 2 k i = ∑ i = 1 k i − 1 = k ( k + 1 ) 2 − 1 \sum_{i=2}^k i = \sum_{i=1}^k i - 1 = \frac{k(k+1)}{2} - 1 i=2ki=i=1ki1=2k(k+1)1

忽略常数项(复杂度分析仅关注主导项),可近似为: ∑ i = 2 k i ≈ k 2 2 \sum_{i=2}^k i \approx \frac{k^2}{2} i=2ki2k2

将其代入 W ( k ) W(k) W(k) 的表达式: W ( k ) ≈ 2 k − 1 ⋅ O ( 1 ) + 2 k ⋅ k 2 2 = O ( 2 k ) + k 2 ⋅ 2 k − 1 W(k) \approx 2^{k-1} \cdot O(1) + 2^k \cdot \frac{k^2}{2} = O(2^k) + k^2 \cdot 2^{k-1} W(k)2k1O(1)+2k2k2=O(2k)+k22k1

由于 k 2 ⋅ 2 k − 1 k^2 \cdot 2^{k-1} k22k1 远大于 O ( 2 k ) O(2^k) O(2k)(当 k k k 足够大时),主导项为 k 2 ⋅ 2 k − 1 k^2 \cdot 2^{k-1} k22k1,因此: W ( k ) = Θ ( k 2 ⋅ 2 k ) W(k) = \Theta(k^2 \cdot 2^k) W(k)=Θ(k22k)
 
步骤6:还原为原变量 n n n,得到最终复杂度 根据最初的变量替换关系 n = 2 k n=2^k n=2k,可推出:

  • k = lg ⁡ n k = \lg n k=lgn(对数定义:若 2 k = n 2^k = n 2k=n,则 k = lg ⁡ n k = \lg n k=lgn);
  • 2 k = n 2^k = n 2k=n

k = lg ⁡ n k=\lg n k=lgn 2 k = n 2^k = n 2k=n 代入 W ( k ) = Θ ( k 2 ⋅ 2 k ) W(k) = \Theta(k^2 \cdot 2^k) W(k)=Θ(k22k),得到: T ( n ) = W ( k ) = Θ ( ( lg ⁡ n ) 2 ⋅ n ) = Θ ( n lg ⁡ 2 n ) T(n) = W(k) = \Theta\left((\lg n)^2 \cdot n\right) = \Theta(n \lg^2 n) T(n)=W(k)=Θ((lgn)2n)=Θ(nlg2n)
 
最终结论 递推式 T ( n ) = 2 T ( n / 2 ) + n lg ⁡ n T(n) = 2T(n/2) + n\lg n T(n)=2T(n/2)+nlgn 的时间复杂度为 Θ ( n lg ⁡ 2 n ) \boxed{\Theta(n \lg^2 n)} Θ(nlg2n)

 

3. 主方法:分治的“快捷公式”

主方法是用序列求和法时得到的一些结果的总结。主方法主要有三条规则。检查递推关系满足哪条规则,如果满足,立马就有答案。

针对标准递推式 T ( n ) = a T ( n / b ) + f ( n ) T(n) = aT(n/b) + f(n) T(n)=aT(n/b)+f(n)(其中 a ≥ 1 , b > 1 a \geq1,b>1 a1,b>1 a a a 是子问题数量, b b b 是子问题规模缩小的比例, f ( n ) f(n) f(n) 是分解与合并的总时间),计算 k = log ⁡ b a k=\log_b a k=logba,再根据 f ( n ) f(n) f(n) n k n^k nk 的关系套用以下规则:

  • 规则1:若存在 ϵ > 0 \epsilon>0 ϵ>0,使得 f ( n ) = O ( n k − ϵ ) f(n)=O(n^{k-\epsilon}) f(n)=O(nkϵ),则 T ( n ) = Θ ( n k ) T(n)=\Theta(n^k) T(n)=Θ(nk)(子问题代价主导);
  • 规则2:若 f ( n ) = Θ ( n k ) f(n)=\Theta(n^k) f(n)=Θ(nk),则 T ( n ) = Θ ( n k lg ⁡ n ) T(n)=\Theta(n^k \lg n) T(n)=Θ(nklgn)(子问题与合并代价平衡);
  • 规则3:若存在 ϵ > 0 \epsilon>0 ϵ>0,使得 f ( n ) = Ω ( n k + ϵ ) f(n)=\Omega(n^{k+\epsilon}) f(n)=Ω(nk+ϵ),且存在 c < 1 c<1 c<1 满足正则条件 a f ( n / b ) ≤ c f ( n ) af(n/b) \leq cf(n) af(n/b)cf(n),则 T ( n ) = Θ ( f ( n ) ) T(n)=\Theta(f(n)) T(n)=Θ(f(n))(合并代价主导)。

便可求出复杂度。

 

例子:二分查找的递推式是 T ( n ) = T ( n / 2 ) + O ( 1 ) T(n)=T(n/2)+O(1) T(n)=T(n/2)+O(1),其中 a = 1 , b = 2 a=1,b=2 a=1,b=2,则 k = log ⁡ 2 1 = 0 k=\log_2 1=0 k=log21=0 f ( n ) = O ( 1 ) = Θ ( n 0 ) f(n)=O(1)=\Theta(n^0) f(n)=O(1)=Θ(n0),套用规则2得 T ( n ) = Θ ( lg ⁡ n ) T(n)=\Theta(\lg n) T(n)=Θ(lgn),与直觉一致。

 

http://www.dtcms.com/a/500109.html

相关文章:

  • CSS核心概念全解析:从入门到精通
  • 公司品牌网站建设常州语言网站建设
  • 北京做商铺的网站网站建设及域名申请 厦门
  • 微网站制作软件无版权视频素材网站
  • 深圳外贸建站模版那些市区做网站群
  • 【Linux】路劲解析-简析inode和dentry关系
  • AI Agent概念 原理 实践
  • 微信公众号的网站开发四川建设厅官方网站文件下载
  • 提供五屏网站建设深圳外贸建站网络推广价格
  • 电脑的 wifi 图标不见了该怎么处理
  • 深入浅出:SQL注入中的逗号绕过技巧剖析
  • (Kotlin高级特性四)kotlin属性委托(如 by lazy) 的原理?
  • 网站美术视觉效果布局设计在线服务平台的跨境电商有哪些
  • k8s(七)pod的配置资源管理
  • 做软件跟网站哪个难沭阳找做网站合伙
  • 智元灵犀X1开源分析-通讯架构
  • 5.1元挂逼VPSW
  • 旅游电子商务网站建设长春做网站wang
  • 智能语义搜索核心算法:全链路技术解析与工程实践,将rag向量检索准确率提升到98%以上……
  • 2025基于springboot的校车预定全流程管理系统
  • 学网站建设需要下载什么太平保险网站
  • 封面型网站首页怎么做做吃穿住行网站
  • macos安装、更新、使用homebrew
  • Vue3+Three.js:第06期 实现立方体旋转动画
  • tp做的网站封装成app网络服务提供者知道或者应当知道网络
  • 江苏城乡建设职业学院网站小程序代码怎么写
  • Web3入门:从MetaMask到Gas机制全解析
  • 区块链技术的五大应用场景
  • 做创意ppt网站店面设计图
  • 登陆建设银行wap网站做网站自己申请域名还是建站公司