开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第4天,点击查看活动详情
递归算法是我们经常遇到的算法,如何分析其时间复杂度是个问题。本文介绍4种求解方法。
一、递归函数复杂度求解
1. 迭代方法
迭代地展开递归式,将其转化为和式,然后求解。
举个例子:
T(n)=2T(2n)+cn
首先将其迭代展开:
T(n)=2T(2n)+cn=22T(22n)+cn+cn=23T(23n)+cn+cn+cn=…=2kT(2kn)+kcn
接下来是关键一步,我们假设当展开到第k次时,递归结束,即2kn=1,接下来要将未知数k全部替换成n,则有:
2kn=1⇒n=2kT(n)=2kT(2kn)+kcn=2kT(1)+kcn=nT(1)+cnlogn=Θ(nlogn)
至此求解完成,T(n)的时间复杂度为Θ(nlogn),如果要求不高的话,可以写低阶函数O。
需要说明的一点是,我们通常将log2n写作logn。
总结一下:
迭代法求解递归函数复杂度:
- 迭代展开,将递归函数展成具有规律的和式。
- 假设第k次展开递归结束,达到递归终点T(1)。
- 利用k与n的关系,将和式里的k全部替换为n的表达式。
- 求解时间复杂度。当式子复杂不易求解时,可以采用放缩的方式来求上界\下界。
2. 变量代换法
可能有某些递归方程,通过变量代换后可以变成我们熟悉的样子,此时可以用这种方法。
举个例子:
T(n)=2T(2n+17)+n
我们发现,这个式子好像和我们刚才求结果的式子的形式差不多,我们做一下处理,令n=m+34:
n=m+34T(n)⇒T(m+34)=2T(2n+17)+n=2T(2m+34)+m+34
令T(m+34)=S(m),则有:
S(m)=2S(2m)+m+34
此时我们便可以依照上个例子,直接给出结论:S(m)=Θ(mlogm),由n=m+34可知,T(n)=Θ(nlogn)。
总结一下:
变量代换求解递归函数复杂度:
- 观察递归函数形式特点,发现与已经做过的类似。
- 找到合适的变量进行代换。
- 求解代换后的时间复杂度。
- 转化为原式的时间复杂度
此方法的缺点很明显:当看不出来合适的变量代换时便不能使用;但是对于有些题目而言,不使用此方法的话,很难求解,举一个例子:
求解:T(n)=2T(n21)+logn令n=2m,则有:T(2m)=2T(22m)+m令T(2m)=S(m),则:S(m)=2S(2m)+m⇒S(m)=Θ(mlogm)⇒T(n)=Θ(lognloglogm)
3. Master定理
该定理用于求解T(n)=aT(bn)+f(n)型函数,其中a≥1,b>0,f(n)为正函数。
Master定理
当满足以上条件时,有以下结论:
- 若f(n)=O(nlogba−ε),ε>0,则T(n)=Θ(nlogba)
- 若f(n)=Θ(nlogba),则T(n)=Θ(nlogbalogn)
- 若f(n)=Ω(nlogba+ε),ε>0,且对于所有充分大的n有af(bn)≤Cf(n),C<1,则T(n)=Θ(f(n))
想必大家看到这一大堆必然头疼,我们直观地来看,上述定理描述了以下含义:
比较f(n)与nlogba阶数的大小:
- 若f(n)小于nlogba,且是多项式地小于,即对于某个常数ε>0,f(n)=O(nlogba−ε),则有T(n)=Θ(nlogba)
- 若f(n)大于nlogba,且是多项式地大于,即对于某个常数ε>0,f(n)=Ω(nlogba+ε),则有T(n)=Θ(f(n))
- 若f(n)与nlogba同阶,则T(n)=Θ(nlogbalgn)=Θ(f(n)logn)
这样一来,我们便可以简单记为这俩谁大就和谁同阶(同时指出是多项式地大\小与),它们同阶时乘上个logn即可。
举个例子:
求解:T(n)=9T(3n)+na=9,b=3,f(n)=n,nlogba=n2故f(n)=n=O(n2−1),ε=1则有T(n)=Θ(n2)
总结一下:
Master定理求解递归函数复杂度
- 判断函数类型是否符合Master定理条件
- 写出a,b,f(n),nlogba,比较f(n),nlogba阶数的大小
- 若不同阶,需同时指出ε(这一点很重要,因为并不是满足条件的所有式子都使用,若不能指出ε,即并不是多项式地大小与,则定理不适用);若同阶,直接写答案
可以看到,使用Master定理极大地简化了运算。但同时,Master定理的局限性较大,一方面是对于递归函数形式的限制,另一方面必须是多项式地大于小于,非多项式大小与的也不适用。
目前不断有学者对Master定理进行拓展,以扩大它的适用范围,但因其较为复杂,本文给出的形式已经满足绝大部分需求,感兴趣的读者可以自行查阅相关文献了解。
4. 先猜后证
顾名思义,首先猜测答案应该是多少,然后适用数学归纳法进行证明。
举个例子:
求解:T(n)=2T(2n+17)+n
这个题我们在前面已经求解过,但还请读者暂时忘记答案。
由于2n与2n+17阶数相同,在n充分大时近似相等,所以我们有理由猜测,当n充分大时,T(2n)≈T(2n+17),故T(n)=2T(2n)+n,易知T(n)=Θ(nlogn),接下来再用数学归纳法进行证明。
这种方法我个人不是很推荐使用,缺点很明显:如果猜的稍微有偏差,则可能造成解不出来;可能猜对了,但数学归纳法证明不出来。总的来说就是适用于数学能力较强的人,我个人还是更建议前三种方法。
但是,我们不能抛弃这种方法,因为在某些极端情况下,猜测答案反而是最优选择,可以通过先猜大范围,然后不断压缩上界,提高下界的方法来达到”逼近“正确答案的目的。
二、总结
本文介绍了4种递归函数的求解方法,在解题的过程中,我们应该考虑以下顺序:Master定理 > 变量代换 > 迭代求解 > 先猜后证。
同时,对于常见的递归形式,应该记住其复杂度,如T(n)=2T(2n)+cn⇒Θ(nlogn)等。