求解递归式,计算时间复杂度

方法一:代换法

代换法主要需要以下两个步骤

1、  猜答案,不需要完全猜出来,不需要知道常熟系数的准确值,而只需要猜出它的形式,比如猜一个递归式的时间复杂度大概是O(n2),即它的运行时间应该是一个常熟乘以n2,可能还会有一些低阶项。

2、  用数学归纳法证明之,设法求出常数系数可以使问题成立

例如 T(n)= 4T(n/2) +n , [T(1) = O(1)]

通过观察该递归式,注意到当n加倍时,输出增加4倍,于是猜测该递归式时间复杂度为O(n2),即T(n) = O(n2) 。不过直接证明时间复杂度是n2有点困难,可以先从一个更简单的开始,比如猜测它的时间复杂度是n3,下面用归纳法证明它。

很显然在n=1的时候是成立的,只需要一个比较大的常数就够了。

在用归纳法证明过程中是不能使用O符号的,所以需要用常熟系数展开它,

假设T(k) ≤ ck3 (k<n) ,带入上面递归式,得到

T(n) ≤ 4c(n/2)3 + n = 1/2cn3+n = cn3-(1/2cn3-n)≤cn3 如果cn3-n≥0

可以看到当c≥1,n≥1的时候,该不等式是成立的,即T(n)小于等于一个常数乘以n3,只需要该常数大于等于1,这样就得到了一个上界,但不是严格意义上的上界,因为我们觉得对于n2它也应该是成立的,下面开始证明n2的情况,于是抄袭上面的步骤再来一次,得到

T(k) ≤ ck2(k<n)

T(n) ≤ 4c(n/2)2 + n =cn2+n= cn2-(-n) 这儿无法得到T(n) ≤cn2 ,假设是错的?囧,看样子假设里需要一个低阶项,于是继续假设

T(k) ≤ c1k2-c2k(k<n)

T(n) ≤4[c1(n/2)2-c2(n/2)]+n=c1n2+(1-2c2)n = c1n2-c2n-(c2-1)n≤c1n2-c2n 如果c2≥1

这样就证明了,对于任意的c1,只要c2大于等于1,那么不等式就成立。但事实上,当n=1的时候,要求c1>c2,不等式才能成立,因此c1要尽可能的大,至少要比c2大。

 

方法二:递归树法

递归树法主要是通过递归树将递归式展开来找到答案,然后再用代换法证明它,因为递归树法是不严谨的。

例如,用递归树法求T(n) = T(n/2) + n2 , 用递归树法将该递归式展开

《求解递归式,计算时间复杂度》

像这样将递归树展开并延伸下去,最终到叶子节点就只剩下T(1),那么该递归树的高度就是logn,因为从顶点n出发,到n/2,到n/4,……最后到1,那么从n到1的折半次数是logn,即高度是logn(应该是一个常数乘以logn,不过没多大关系)。而最下面叶子节点的数目是n,因为从第一层往下,节点数变化为1,2,4,8……,如果树的高度是h,那么就会有2h个叶节点,而高度是logn,那么2logn=n。那么,整体所做的工作加起来就是T(n)了

T(n) = [1+1/2+1/4+……]n2 = 2n2,于是可知时间复杂度为T(n) = O(n2)。

再例如,用递归树法求T(n) = T(n/4)+T(n/2)+n2 ,下面用递归树的方法将该递归式展开

《求解递归式,计算时间复杂度》

最后,求叶子节点的数目有点麻烦,因为分支的递归速度是不一样的,左边降低到n/16的时候,右边才降低到n/4,左边子树的高度将会比右边子树的高度要小。可以看到叶子节点的数目必然小于n,因为最开始的问题大小是n,然后递归成一个n/4和n/2的两个子问题,直到最后递归到1停止,而n/4+n/2 < n , 所以最后叶子节点的数目不会超过n,将每层求和就得到T(n),经过观察发现一个等比数列,于是数学归纳法开始派上用场

T(n) = (1+5/16+25/256+……)n2≤2n2 = O(n2)   于是得到该递归式时间复杂度为O(n2),因为是猜出来的等比数列,于是需要用数学归纳法证明之,就又变成方法一中代换法求证了。

方法三:主方法 (master method)

该方法仅适用于特定格式的递归式

《求解递归式,计算时间复杂度》

同时要求f(n)渐进趋正,即当n->无穷时,f(n)>0。(我觉得上图中第2,3中少了个logn,具体请参考算法导论一书中对时间复杂度的讨论)

例如:

T(n)=4T(n/2)+n , 则a=4,b=2,f(n)=n,计算nlog(b,a)=n2>f(n) , 满足模式一,因此T(n) = nlog(b,a)=O(n2)

T(n)=4T(n/2)+n2,则根据上面计算,满足模式二,因此T(n)=O(n2logn)

T(n)=4T(n/2)+n3,满足模式三,T(n)=O(n3)

对于该方法的正确性,可以通过递归树的方法证明,懒的画了,可以在大脑里构思出这样一个草图:

在第一层,f(n)分解为a个子问题,每个子问题都是f(n/b),第二层每个子问题又分解为a个子问题,每个问题都是f(n/b2)……这样递归分解下去,最后的叶子还是O(1),整个树的高度就是log以b为底n的对数,整个的叶子节点数目为a的log以b为底n的对数次方(alog(b,n)),即nlog(b,a)个叶子节点。每个分支的递减速度是一样的,将每层都加在一起便得到T(n) ,此时就需要对f(n)的情况进行讨论(于是就是上面的1,2,3)。

    原文作者:算法小白
    原文地址: https://www.cnblogs.com/web-application-security/archive/2012/06/15/how_to_solve_recurrences.html
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞