递归算法的时间复杂度分析
在算法分析中,当一个算法中包含递归调用时,其时间复杂度的分析会转化为一个递归方程求解。实际上,这个问题是数学上求解渐近阶的问题,而递归方程的形式多种多样,其求解方法也是不一而足,比较常用的有以下四种方法:
方法一:代换法
代换法主要需要以下两个步骤
1、 猜答案,不需要完全猜出来,不需要知道常熟系数的准确值,而只需要猜出它的形式,比如猜一个递归式的时间复杂度大概是O(n2),即它的运行时间应该是一个常熟乘以n2,可能还会有一些低阶项。
方法二:递归树法
递归树法主要是通过递归树将递归式展开来找到答案,然后再用代换法证明它,因为递归树法是不严谨的。
例如,用递归树法求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)。