『数学杂谈』递归式复杂度求解/渐进式小记

  关于递归式复杂度求解的一些想法。

  虽然说具体数学有一整章讲渐进式,但鉴于学这个性价比太低了,基本也用不到,所以很多有关渐进式的实用知识会在本文总结。

  接下来进入正题。

渐进式

  很多时候,我们并不能很好的得知一个式子的封闭形式,但是对于这个式子知道他的增长速度也是极好的。这里用来表示这种渐进的符号最常用的符号有两种: OΘ 。在算法竞赛,一般直接使用 O 即可,但是在实际数学使用中两种符号其实是有区别的: O 表示的是 渐进上界(asymptotically upper bound) ,表示式子的量级不会超过这个数;而 Θ 表示的是 渐近紧确界(asymptotically tight bound) ,也就是说记号 O 并不含式子渐进下界的信息,不过在关心时间复杂度上界的算法竞赛中下界并不重要,因此直接用 O 是没有问题的。当然还有记号 Ω 表示 渐进下界(asymptotically lower bound) ,只不过它不太常用,我们就不对其多加讨论。

  计算渐进式的方法有很多,下面会一一介绍。

主定理及其局限性

  这是本文十分重要的一个点。这里先介绍一下主定理,这是一个非常好的求解递归式渐进的方法(证明略):

Theorem:

 a1,b1  f(n) T(n)=aT(nb)+f(n)  nb  nb  nb 1. ε>0  使 f(n)=O(nlogbaε)  T(n)=Θ(nlogba)2. k0  使 f(n)=O(nlogbalgkn)  T(n)=Θ(nlogbalgk+1n)3. ε>0  使 f(n)=O(nlogba+ε)  0<c<1  N 使 n>N  af(nb)cf(n)  T(n)=Θ(f(n))

  主定理的适用范围是非常广的,但是它对下面这个式子束手无策:

(1)T(n)=4nT(n)+n

  发现主定理用不了,因为子问题里的 n=nn 得到 b=n ,这并不是一个常数,此时主定理就用不了了。

  除了上式外,看到下面这个递归式:

(2)T(n)=T(n2)+T(n4)+T(n8)+n

这个式子的子问题并不是平均划分的,因此也就不能用主定理。

  我们再看一个式子:

(3)T(n)=4T(n4)+nlgn

此时该式子不符合主定理的三种情况,也是不能用主定理的。

不那么暴力的暴力

  对于不能用主定理解决的递归式,《算法导论》中推荐使用递归树+数学归纳法解决,但是这样工作量过于巨大了,会显得很蠢,还不如乱猜再证明来的快,此时就十分的难受,不知道怎么整。
  为了让我们能更简洁与优美的暴力,采用更好的方法是必要的。我们尝试在递归树的基础上进行优化。就像记忆化搜索可以优化深度优先搜索一样,我们可以对每一个可能出现的子问题考虑它对答案的贡献。
  拿 (1) 式举例,我们无需列出一整棵递归树,只需对每个子问题统计贡献即可。用 w(x) 表示子问题 T(x) 的贡献,就可以有下面的表:

x w(x)
n n
n 4n×n=4n
n (4n)(4n)(n)=16n

  相信对数字敏感的人无需列表即可感性地证明规律,即使不太敏感,表的前三项也足够找到规律:

w(n0.5x)=4xn

那么设 n=2k 那么层数就应该是:

log2k=log2log2n

总的复杂度就会是:

i=0log2log2n4in

i=0log2log2n4i4log2log2n

所以答案为:

4log2log2nn=22log2log2nn=(2log2log2n)2n=O(n(log2n))

  如果具有较好的和式计算能力的话,这种做法也是可以得出和主定理一样的结果的。下面是 Codeforces Round 960 F题 的一种错误做法最劣时间复杂度分析,它是一个基于递归的分治算法。递归树这一步就省略了,得出的式子是这样的:

T(n)=log2n+2log2(n2)+4log2(n4)+log2n=log2n+k=1log2n2klog2(n2k)

我们把后面的和式拎出来处理:

k=1log2n2klog2(n2k)=k=1log2n2k(log2nk)=log2nk=1log2n2kk=1log2nk2k

具体数学一书中有对和式后面一个和式的化简,这里不赘述化简过程: k=1mk2k=(m1)2m+1+2 ,所以:

log2nk=1log2n2kk=1log2nk2k=log2n(2log2n+12)(log2n1)2log2n+1+2=log2n(2n2)(log2n1)2n+2=2nlog2n2log2n2nlog2n+2n+2=2n2log2n+2

带回到原式就有 2nlog2n+2 ,即单次询问时间复杂度是 O(n) 的,并不能通过。

  不妨再来一组。我们来解决式 (2) ,而这甚至表都可以不列出来。不难发现层数最为 log2n ,而层贡献为 × ,假设当前层为 n12k ,相当于一次能走一步、两步或三步,走 k 步的方案数, OGF 搞起,但是没搞出来(?),但是可以从组合的角度近似地看作把 k 个数分成三段,那么这个系数就应该是 O(k2) 的,那么答案就是:

i=0log2ni212in=O(n)

  最后我们来搞定式 (3) ,依然是把层数算出来,是 log4n ,那么答案就是:

i=0log4n4in4ilgn4i=i=0log4nnlgn4i

然后发现式子并不能化简到封闭形式,此时我们就需要下面的定理。

Akra-Bazzi定理

Theorem:

 g(x)  T(x)={Θ(1),1xX0i=1kaiT(bix)+g(x),n>X0 k1,ai>0,0<bi<1) X0  1ik  X0>1bi  X0>11bi g(x)  p  i=1kaibip=1  T(x)=Θ(xp(1+1xg(u)up+1du))

  其中的多项式增长条件可以简易地理解为 c>0,|g(x)|O(xc)
  开了之后我们再回到式 (3)p 显然为 1 ,那么代入定理得到:

T(n)=Θ(n(1+1nxlgxx2dx))=Θ(n(1+1n1xlgxdx))=Θ(n+(1+lglgn))=Θ(nlglgn)

  Akra-Bazzi 定理原论文里的证明用了一种称为 阶变换(Order Transform) 的技巧,还涉及泛函分析,这些笔者还在学习中。当然粗暴一点的证明有数学归纳法,这里受限于本人能力不足,不做证明。

总结

  总结一下,对于一般的递归式,可通过主定理求渐进解。而对于 b 不是常数的情形,可以分层分析贡献。最后对于 g(n) 满足多项式增长的式子,可以尝试使用 Akra-Bazzi 定理。

posted @   Black_Crow  阅读(82)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
点击右上角即可分享
微信分享提示