(三)递归函数复杂度分析——算法设计与分析

280 阅读4分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第4天,点击查看活动详情

递归算法是我们经常遇到的算法,如何分析其时间复杂度是个问题。本文介绍4种求解方法。


一、递归函数复杂度求解

1. 迭代方法

迭代地展开递归式,将其转化为和式,然后求解。

举个例子:

T(n)=2T(n2)+cnT(n)=2T(\frac{n}{2} )+cn

首先将其迭代展开:

T(n)=2T(n2)+cn=22T(n22)+cn+cn=23T(n23)+cn+cn+cn==2kT(n2k)+kcn\begin{aligned} T(n)&=2T(\frac{n}{2} )+cn\\ &=2^2T(\frac{n}{2^2} )+cn+cn\\ &=2^3T(\frac{n}{2^3} )+cn+cn+cn\\ &=\dots \\ &=2^kT(\frac{n}{2^k} )+kcn\\ \end{aligned}

接下来是关键一步,我们假设当展开到第kk次时,递归结束,即n2k=1\frac{n}{2^k} =1,接下来要将未知数kk全部替换成nn,则有:

n2k=1n=2kT(n)=2kT(n2k)+kcn=2kT(1)+kcn=nT(1)+cnlogn=Θ(nlogn)\frac{n}{2^k} =1 \Rightarrow n = 2^k\\ \begin{aligned} T(n)&=2^kT(\frac{n}{2^k} )+kcn\\ &=2^kT(1)+kcn \\ &=nT(1)+cn \log n\\ &=\Theta(n\log n)\\ \end{aligned}

至此求解完成,T(n)T(n)的时间复杂度为Θ(nlogn)\Theta(n\log n),如果要求不高的话,可以写低阶函数OO

需要说明的一点是,我们通常将log2n\log _{2}{n}写作logn\log n


总结一下:

迭代法求解递归函数复杂度:

  1. 迭代展开,将递归函数展成具有规律的和式。
  2. 假设第kk次展开递归结束,达到递归终点T(1)T(1)
  3. 利用kknn的关系,将和式里的kk全部替换为nn的表达式。
  4. 求解时间复杂度。当式子复杂不易求解时,可以采用放缩的方式来求上界\下界。

2. 变量代换法

可能有某些递归方程,通过变量代换后可以变成我们熟悉的样子,此时可以用这种方法。

举个例子:

T(n)=2T(n2+17)+nT(n)=2T(\frac{n}{2} +17)+n

我们发现,这个式子好像和我们刚才求结果的式子的形式差不多,我们做一下处理,令n=m+34n=m+34

n=m+34T(n)=2T(n2+17)+nT(m+34)=2T(m2+34)+m+34n=m+34\\ \begin{aligned} T(n)&=2T(\frac{n}{2} +17)+n\\ \Rightarrow T(m+34)&=2T(\frac{m}{2} +34)+m+34\\ \end{aligned}

T(m+34)=S(m)T(m+34) = S(m),则有:

S(m)=2S(m2)+m+34S(m)=2S(\frac{m}{2})+m+34

此时我们便可以依照上个例子,直接给出结论:S(m)=Θ(mlogm)S(m)=\Theta (m\log m),由n=m+34n=m+34可知,T(n)=Θ(nlogn)T(n)=\Theta (n\log n)


总结一下:

变量代换求解递归函数复杂度:

  1. 观察递归函数形式特点,发现与已经做过的类似。
  2. 找到合适的变量进行代换。
  3. 求解代换后的时间复杂度。
  4. 转化为原式的时间复杂度

此方法的缺点很明显:当看不出来合适的变量代换时便不能使用;但是对于有些题目而言,不使用此方法的话,很难求解,举一个例子:

求解:T(n)=2T(n12)+lognn=2m,则有:T(2m)=2T(2m2)+mT(2m)=S(m),则:S(m)=2S(m2)+mS(m)=Θ(mlogm)T(n)=Θ(lognloglogm)求解:T(n)=2T(n^{\frac{1}{2}})+\log n \\ 令n=2^m,则有:\\ T(2^m)=2T(2^{\frac{m}{2}})+m \\ 令T(2^m)=S(m),则:\\ S(m)=2S(\frac{m}{2})+m\\ \Rightarrow S(m)=\Theta(m\log m)\\ \Rightarrow T(n)=\Theta(\log n \log\log m)

3. Master定理

该定理用于求解T(n)=aT(nb)+f(n)T(n)=aT(\frac{n}{b})+f(n)型函数,其中a1,b>0a\ge 1,b>0f(n)f(n)为正函数。

Master定理

当满足以上条件时,有以下结论:

  1. f(n)=O(nlogbaε),ε>0f(n)=O(n^{\log_ba-\varepsilon}),\varepsilon>0,则T(n)=Θ(nlogba)T(n)=\Theta(n^{log_ba})
  2. f(n)=Θ(nlogba)f(n)=\Theta(n^{\log_ba}),则T(n)=Θ(nlogbalogn)T(n)=\Theta(n^{log_ba}\log n)
  3. f(n)=Ω(nlogba+ε),ε>0f(n)=\Omega(n^{\log_ba+\varepsilon}),\varepsilon>0,且对于所有充分大的nnaf(nb)Cf(n),C<1af(\frac{n}{b})\leq Cf(n),C<1,则T(n)=Θ(f(n))T(n)=\Theta(f(n))

想必大家看到这一大堆必然头疼,我们直观地来看,上述定理描述了以下含义:

比较f(n)f(n)nlogban^{\log_b a}阶数的大小:

  1. f(n)f(n)小于nlogban^{\log_b a},且是多项式地小于,即对于某个常数ε>0,f(n)=O(nlogbaε)\varepsilon >0,f(n)=O(n^{\log_ba-\varepsilon}),则有T(n)=Θ(nlogba)T(n)=\Theta (n^{\log_b a})
  2. f(n)f(n)大于nlogban^{\log_b a},且是多项式地大于,即对于某个常数ε>0,f(n)=Ω(nlogba+ε)\varepsilon >0,f(n)=\Omega(n^{\log_ba+\varepsilon}),则有T(n)=Θ(f(n))T(n)=\Theta (f(n))
  3. f(n)f(n)nlogban^{\log_b a}同阶,则T(n)=Θ(nlogbalgn)=Θ(f(n)logn)T(n)=\Theta (n^{\log_b a}\lg n)=\Theta (f(n)\log n)

这样一来,我们便可以简单记为这俩谁大就和谁同阶(同时指出是多项式地大\小与),它们同阶时乘上个logn\log n即可。

举个例子:

求解:T(n)=9T(n3)+na=9,b=3,f(n)=n,nlogba=n2f(n)=n=O(n21),ε=1则有T(n)=Θ(n2)求解:T(n)=9T(\frac{n}{3})+n \\ a=9,b=3,f(n)=n,n^{log_ba}=n^2\\ 故f(n)=n=O(n^{2-1}),\varepsilon=1\\ 则有T(n)=\Theta(n^2)

总结一下:

Master定理求解递归函数复杂度

  1. 判断函数类型是否符合Master定理条件
  2. 写出a,b,f(n),nlogbaa,b,f(n),n^{\log_ba},比较f(n),nlogbaf(n),n^{\log_ba}阶数的大小
  3. 若不同阶,需同时指出ε\varepsilon(这一点很重要,因为并不是满足条件的所有式子都使用,若不能指出ε\varepsilon,即并不是多项式地大小与,则定理不适用);若同阶,直接写答案

可以看到,使用Master定理极大地简化了运算。但同时,Master定理的局限性较大,一方面是对于递归函数形式的限制,另一方面必须是多项式地大于小于,非多项式大小与的也不适用。

目前不断有学者对Master定理进行拓展,以扩大它的适用范围,但因其较为复杂,本文给出的形式已经满足绝大部分需求,感兴趣的读者可以自行查阅相关文献了解。


4. 先猜后证

顾名思义,首先猜测答案应该是多少,然后适用数学归纳法进行证明。

举个例子:

求解:T(n)=2T(n2+17)+n求解:T(n)=2T(\frac{n}{2}+17)+n

这个题我们在前面已经求解过,但还请读者暂时忘记答案。

由于n2\frac{n}{2}n2+17\frac{n}{2}+17阶数相同,在nn充分大时近似相等,所以我们有理由猜测,当nn充分大时,T(n2)T(n2+17)T(\frac{n}{2})\approx T(\frac{n}{2}+17),故T(n)=2T(n2)+nT(n)=2T(\frac{n}{2})+n,易知T(n)=Θ(nlogn)T(n)=\Theta(n\log n),接下来再用数学归纳法进行证明。

这种方法我个人不是很推荐使用,缺点很明显:如果猜的稍微有偏差,则可能造成解不出来;可能猜对了,但数学归纳法证明不出来。总的来说就是适用于数学能力较强的人,我个人还是更建议前三种方法。

但是,我们不能抛弃这种方法,因为在某些极端情况下,猜测答案反而是最优选择,可以通过先猜大范围,然后不断压缩上界,提高下界的方法来达到”逼近“正确答案的目的。


二、总结

本文介绍了4种递归函数的求解方法,在解题的过程中,我们应该考虑以下顺序:Master定理 > 变量代换 > 迭代求解 > 先猜后证

同时,对于常见的递归形式,应该记住其复杂度,如T(n)=2T(n2)+cnΘ(nlogn)T(n)=2T(\frac{n}{2} )+cn \Rightarrow \Theta (n\log n)等。