转自:http://www.cnblogs.com/python27/archive/2011/12/09/2282486.html

开篇前言:为什么写这篇文章?笔者目前在学习各种各样的算法,在这个过程中,频繁地碰到到递归思想和分治思想,惊讶于这两种的思想的伟大与奇妙的同时,经常要面对的一个问题就是,对于一个给定的递归算法或者用分治思想缩小问题规模的算法,如何求解这个算法的时间复杂度呢?在google过很多的博文后,感觉这些博文总结的方法,有很好优秀的地方,但是都不够全面,有感于此,笔者决定总结各家之长,作此博文,总结各种方法于此,有不足之处,欢迎各位批评指证!

  在算法的分析中,当一个算法中包含递归调用时,其时间复杂度的分析会转化成为一个递归方程的求解。而对递归方程的求解,方法多种多样,不一而足。本文主要介绍目前主流的方法:代入法,迭代法,公式法,母函数法,差分方程法。


  【代入法】代入法首先要对这个问题的时间复杂度做出预测,然后将预测带入原来的递归方程,如果没有出现矛盾,则是可能的解,最后用数学归纳法证明。

  【举   例】我们有如下的递归问题:T(n)=4T(n/2)+O(n),我们首先预测时间复杂度为O(n2),不妨设T(n)=kn2(其中k为常数),将该结果带入方程中可得:左=kn2,右=4k(n/2)2+O(n)=kn2+O(n),由于n2的阶高于n的阶,因而左右两边是相等的,接下来用数学归纳法进行验证即可。


  【迭代法】迭代法就是迭代的展开方程的右边,直到没有可以迭代的项为止,这时通过对右边的和进行估算来估计方程的解。比较适用于分治问题的求解,为方便讨论起见,给出其递归方程的一般形式:

  【举   例】下面我们以一个简单的例子来说明:T(n)=2T(n/2)+n2,迭代过程如下:

  容易知道,直到n/2^(i+1)=1时,递归过程结束,这时我们计算如下:

  到这里我们知道该算法的时间复杂度为O(n2),上面的计算中,我们可以直接使用无穷等比数列的公式,不用考虑项数i的约束,实际上这两种方法计算的结果是完全等价的,有兴趣的同学可以自行验证。


  【公式法】这个方法针对形如:T(n) = aT(n/b) + f(n)的递归方程。这种递归方程是分治法的时间复杂性所满足的递归关系,即一个规模为n的问题被分成规模均为n/b的a个子问题,递归地求解这a个子问题,然后通过对这a个子问题的解的综合,得到原问题的解。这种方法是对于分治问题最好的解法,我们先给出如下的公式:

  公式记忆:我们实际上是比较n^logba和f(n)的阶,如果他们不等,那么T(n)取他们中的较大者,如果他们的阶相等,那么我们就将他们的任意一个乘以logn就可以了。按照这个公式,我们可以计算【迭代法】中提到的例子:O(f(n))=O(n2),容易计算另外一个的阶是O(n),他们不等,所以取较大的阶O(n2)。太简单了,不是吗?

  需要注意:上面的公式并不包含所有的情况,比如第一种和第二种情况之间并不包含下面这种情况:f(n)是小于前者,但是并不是多项式的小于前者。同样后两种的情况也并不包含所有的情况。为了好理解与运用的情况下,笔者将公式表述成如上的情况,但是并不是很严谨,关于该公式的严密讨论,请看这里。但是公式的不包含的情况,我们很少很少碰到,上面的公式适用范围很广泛的。

  特别地,对于我们经常碰到的,当f(n)=0时,我们有:


  【母函数法】母函数是用于对应于一个无穷序列的幂级数。这里我们解决的递归问题是形如:T(n)=c1T(n-1)+c2T(n-2)+c3T(n-3)+...+ckT(n-k)+f(n)。为说明问题简便起见,我们选择斐波那契数列的时间复杂度作为例子进行讨论。

  【举  例】斐波那契数列递归公式:T(n)=T(n-1)+T(n-2)。这里我们假设F(n)为第n项的运算量。则容易得到:F(n)=F(n-1)+F(n-2),其中F(1)=F(2)=1.我们构造如下的母函数:G(x)=F(1)x+F(2)x2+F(3)x3+......,我们可以推导如下:

  上面的方法计算相对来说是比较简单的,关键在于对于母函数的理解,刚开始的时候可能不是很好理解,对于母函数可以参考这里和维基百科这里。


  【差分方程法】可以将某些递归方程看成差分方程,通过解差分方程的方法来解递归方程,然后对解作出渐近阶估计。这里我们只考虑最长常见的递归形式,形如:T(n)=c1T(n-1)+c2T(n-2)+c3T(n-3)+...+ckT(n-k)+f(n),其中c1,c2,...ck为常数且不等于0;我们对该方程的求解如下:

  对应上面的齐次方程的特征方程为:

  如果解得t=r是该特征方程的m重根,则这m个解的形式为:{rn     n*rn      n2rn   ...    nm-1rn},其余的关于复数解的形式和普通的线性方程组的形式类似,不再赘述。接下来,我们要求解该方程的对应非齐次方程组的通解,这里我们针对该方程的特殊形式,不加证明地给出如下的通解形式:

  则和线性代数中的解一样,原方程的解等于齐次方程组的通解+特解,即:

  最后由初始条件确定a(i)的值即可。

  为了帮助理解,我们举两个例子看看,就明白是怎么回事了。

  【举 例1】递归方程如下:

(1)写出对应齐次方程的特征方程:

得到基础解系为:{t1n,  t2n}

(2)计算特解,对于本题,直接观察得特解为:-8

(3)得到原方程解的形式为:T(n)=a0t1n+a1t2n-8

(4)代入n=0,n=1的情况,得到a0,a1,最后可得:

  可以看到该方程形式和上面讨论过的斐波那契数列只差一个常数8,因而两者的时间复杂度是相同的。有兴趣的同学可以按照这个方法再次计算斐波那契数列的时间复杂度验证一下。

  【举  例2】递归方程如下:

(1)计算对应齐次方程的基础解析:

特征方程为:C(t)=t^2-4t-4=0,得到一个2重根t=2.因而其基础解为:{2n      n*2n}

(2)由于f(n)=n*2n,对应上面表格的最后一种情况,得到特解形式为:T(n)=n2(p0+p1n)2n代入原递归方程可得:p0=1/2,p1=1/6

(3)原方程解的形式为:T(n)=a0*2n+a1*n*2n+n2(1/2+n/6)2n,代入T(0),T(1)得:a0=a1=0

(4)综上:T(n)=n2(1/2+n/6)2n

因而时间复杂度为:O(n32n)


References:

[1]青青的专栏:http://blog.csdn.net/metasearch/article/details/4428865

[2]心灵深处博客:http://blog.csdn.net/metasearch/article/details/4428865

[3]wikipedia中文:母函数

[4]母函数的性质和应用:http://www.doc88.com/p-39037791334.html

[5]关于递归算法时间复杂度分析的讨论:http://wenku.baidu.com/view/719b053331126edb6f1a1091.html

[6][置顶]递归方程组解的渐进阶的求法——差分方程法:http://blog.csdn.net/explore_knight/article/details/1788046

注:

1)本博客所有的代码环境编译均为win7+VC6。所有代码均经过博主上机调试。

2)博主python27对本博客文章享有版权,网络转载请注明出处http://www.cnblogs.com/python27/。对解题思路有任何建议,欢迎在评论中告知。

递归算法的时间复杂度终结篇相关推荐

  1. 【算法16】递归算法的时间复杂度终结篇

    递归算法的时间复杂度终结篇 备忘地址:[算法16]递归算法的时间复杂度终结篇

  2. Linux调度系统全景指南(终结篇)

    点击上方蓝字关注公众号,更多经典内容等着你 | 导语本文主要是讲Linux的调度系统, 本篇是终结篇,主要讲当前多核系统调度策略和调度优化,调度可以说是操作系统的灵魂,为了让CPU资源利用最大化,Li ...

  3. 递归算法及其时间复杂度分析

    引言 "递归" 一词是比较专业的计算机术语,在现实生活中,有一个更可爱的词--"套娃".如果把"递归算法"叫做"套娃算法" ...

  4. 算法导论------递归算法的时间复杂度求解

    目录 1.算法设计与分析概述 2.非递归算法分析 3.递归算法分析 3.1利用数列知识 3.2代入法 3.3递归树 3.4主方法求解递推式 4.参考资料 1.算法设计与分析概述   在总结递归算法的时 ...

  5. 带你了解递归算法的时间复杂度

    用这篇article来给大家通透的讲一讲递归算法的时间复杂度. 同一道题目,同样使用递归算法,有的同学会写出了O(n)的代码,有的同学就写出了O(logn)的代码. 这是为什么呢? 如果我们对递归的时 ...

  6. 递归算法的时间复杂度

    递归算法的时间复杂度 总结 本篇通过一道面试题,一个面试场景,来好好分析一下如何求递归算法的时间复杂度. 相信很多同学对递归算法的时间复杂度都很模糊,那么这篇来给大家通透的讲一讲. 同一道题目,同样使 ...

  7. 看看C# 6.0中那些语法糖都干了些什么(终结篇)

    终于写到终结篇了,整个人像在梦游一样,说完这一篇我得继续写我的js系列啦. 一:带索引的对象初始化器 还是按照江湖老规矩,先扒开看看到底是个什么玩意. 1 static void Main(strin ...

  8. 分布式事务科普(终结篇)

    <分布式事务科普>是我在YiQing期间整理的一篇科普型文章,内容共计两万五千字左右,应该算是涵盖了这个领域的大多数知识点.篇幅较长,遂分为上下两篇发出.上篇为<分布式事务科普--初 ...

  9. Java异常处理终结篇——如何进行Java异常处理设计

    [本文转自于Java异常处理终结篇--如何进行Java异常处理设计] 有一句这样话:一个衡量Java设计师水平和开发团队纪律性的好方法就是读读他们应用程序里的异常处理代码. 本文主要讨论开发Java程 ...

最新文章

  1. 微服务实战(六):选择微服务部署策略
  2. Flask实战2问答平台-完成登录注册功能
  3. uva 755 487--3279
  4. spring 异步返回结果_使用Spring Integration聚合异步结果
  5. mysql集群多管理节点_项目进阶 之 集群环境搭建(三)多管理节点MySQL集群
  6. java两个长度不同数组_两组数组,长度不一样,如果其中一个数组的值在另一个中不存在,则不符合要求.怎么算?...
  7. 判断本地是否存在Jquery文件,如果不存在则使用CDN加速的Jquery文件
  8. Spring : Spring定义Bean的两种方式:lt; bean gt;和@Bean
  9. VMWare关闭beep声
  10. 学习笔记-Rabin-Karp哈希
  11. plt图像保存到pdf文件
  12. Pyinstaller:moviepy打包报错AttributeError: module ‘moviepy.audio.fx.all‘ has no attribute ‘audio_fadein‘
  13. Bundle Adjustment — A Modern Synthesis(一)
  14. 搭建jpress个人博客
  15. iOS XibKits-- Label内边距设置
  16. 【萧蕊冰】你知道ui设计属于什么行业吗?
  17. CSR867x开发基础教学 - CSR8675_sink工程如何自定义语音提示音
  18. 智能眼镜时代即将来临,它会比智能手机更人性化吗?
  19. Layer——弹出层
  20. 百度 ASTAR 2010 (二)

热门文章

  1. 机器人编程对计算机有什么帮助吗,小孩学机器人编程有什么用
  2. Windows文件资源管理器“快速访问”的隐藏、关闭及开启(win10)
  3. some kotlin libraries attached to this project were compiled with a newer kotlin compiler and can‘t
  4. 在线教程!C++如何在云应用中快速实现编译优化?
  5. 数据分析师,年终述职报告模板来了!
  6. 【富文本】Windows10数字权利
  7. (转)android多国语言适配
  8. .NET开发人员必备电子书下载
  9. IIS 配置允许跨域访问
  10. learn git branching学习整理3