递归 - 时间复杂度

在本文中, 我们主要介绍如何分析递归算法程序中的时间复杂度。.
在一个递归程序中, 它的时间复杂度 O(T) 一般来说就是他总共递归调用的次数 (定义为 R) 以及每次调用时所花费的耗时 (定义为 O(s)) ,这样我们就可以得出:
(T) = R * O(T) = R∗O(s)
下面让我们来看几个栗子:
 

线性的栗子


正如之前的问题 printReverse所描述的, 需要把一个字串逆序输出. 其中一种递归的解法如下所示:
printReverse(str) = printReverse(str[1...n]) + print(str[0])
其中 str[1...n] 是输入的字串 str 去除了首字母str[0]的切分子串, .
显而易见,这个算法会连续调用 n 次, 这个 n 也就该输入字串的长度. 在每次递归的最后, 我们只打印首字母, 因此该算法每次调用递归所耗费的时间为常量, 即为 {\mathcal{O}(1)}O(1).
把次数和每次耗时进行合计,该递归程序 printReverse(str) 的耗时即为 (printReverse) = n * O(1) = O(printReverse)=n∗O(1)=O(n).
 

执行树


对于递归函数, 像上面的线性化递归调用的栗子其实是很少的,更多的是非线性的. 例如, 之前章节我们讨论的 Fibonacci number ,它的递归关系就定义为更复杂的 f(n) = f(n-1) + f(n-2). 乍看之下, 很难一下子去计算出斐波那契函数的递归调用次数 -_-.
在这个例子里, 我们最好使用 execution tree 这个工具可以用来直观地表示递归程序的执行流. 树中的每一个节点都表示每次对应的递归程序调用. 因此,树中的节点总数与整个递归过程调用的总数相对应。
递归函数的执行树会形成一个 n-ary tree, 其中n 就是这个程序执行下来递归调用的次数. 例如, 斐波那契函数的执行流就是一个二叉树, 如下图所示就是计算 f(4) 的流程树:
 
在一个 n 层的满二叉树, 所有节点数总和应该是 
2^n - 1
 
 
. 因此, 对于递归程序 f(n) 总调用次数的上限也应该是 
{2^n -1}
 
. 所以, 我们得出了递归程序 f(n) 的时间复杂度即为 
{\mathcal{O}(2^n)}
 
 

记忆化


在前面的章节中, 我们讨论过用来优化递归算法时间复杂度的记忆化方法. 通过存储和重复使用中间变量, 记忆化能够极大地降低递归程序的调用次数, 换个说法就是减少执行树中的递归调用分支. 在分析试用了记忆化的递归调用程序的时间复杂度时,千万要记得考虑这种(分支减少的)情况。.
让我们重新再回看前面斐波那契额数列的栗子. 使用记忆化方法的话,我们每次都将斐波那契额数列在 n.节点下的存储, 于是我们可以确保对于每个节点计算需要的递归调用只需要一次. 而且我们知道斐波那契额数列的递归关系是每个 f(n) 都依赖前一个 n-1 的结果. 最终使得计算 f(n) 只调用 n-1 次 之前已经计算好的结果即可. 
现在, 我们可以很轻易的通过前面介绍的公式 O(1)∗n=O(n) .来计算斐波那契额数列函数的时间复杂度。记忆化不仅仅优化算法的时间复杂度,同样也简化了对于时间复杂度的计算。
在下一篇文章中, 我们将讨论如何估算递归程序的空间复杂度.
 
 
 
 原文地址:https://leetcode.com/explore/learn/card/recursion-i/256/complexity-analysis/1669/
 
 
 

LeetCode 递归(Recursion) 培训专题 讲解文章翻译 (附链接)的更多相关文章

  1. LeetCode递归 -2(Recursion) 培训专题 讲解文章翻译 (附链接) (2019-04-09 15:50)

    递归 - 空间复杂度  在本文中, 我们将讨论如何分析递归算法的空间复杂度. 在计算递归算法的空间复杂度时,最需要考虑的两个部分就是: 递归相关空间 (recursion related space) ...

  2. Activity Process Task Application 专题讲解

    Activity Process Task Application 专题讲解 Activity.和进程 为了阅读方便,将文档转成pdf http://files.cnblogs.com/franksu ...

  3. Leetcode之回溯法专题-216. 组合总和 III(Combination Sum III)

    Leetcode之回溯法专题-216. 组合总和 III(Combination Sum III) 同类题目: Leetcode之回溯法专题-39. 组合总数(Combination Sum) Lee ...

  4. 算法与数据结构基础 - 递归(Recursion)

    递归基础 递归(Recursion)是常见常用的算法,是DFS.分治法.回溯.二叉树遍历等方法的基础,典型的应用递归的问题有求阶乘.汉诺塔.斐波那契数列等,可视化过程. 应用递归算法一般分三步,一是定 ...

  5. Atitit  循环(loop), 递归(recursion), 遍历(traversal), 迭代(iterate).

    Atitit  循环(loop), 递归(recursion), 遍历(traversal), 迭代(iterate). 1.1. 循环算是最基础的概念, 凡是重复执行一段代码, 都可以称之为循环. ...

  6. 循环(loop), 递归(recursion), 遍历(traversal), 迭代(iterate)的区别

    表示“重复”这个含义的词有很多, 比如循环(loop), 递归(recursion), 遍历(traversal), 迭代(iterate). 循环算是最基础的概念, 凡是重复执行一段代码, 都可以称 ...

  7. 003_循环(loop), 递归(recursion), 遍历(traversal), 迭代(iterate)的区别

    表示“重复”这个含义的词有很多, 比如循环(loop), 递归(recursion), 遍历(traversal), 迭代(iterate). 循环算是最基础的概念, 凡是重复执行一段代码, 都可以称 ...

  8. Leetcode之分治法专题-169. 求众数(Majority Element)

    Leetcode之分治法专题-169. 求众数(Majority Element) 给定一个大小为 n 的数组,找到其中的众数.众数是指在数组中出现次数大于 ⌊ n/2 ⌋ 的元素. 你可以假设数组是 ...

  9. Leetcode之回溯法专题-212. 单词搜索 II(Word Search II)

    Leetcode之回溯法专题-212. 单词搜索 II(Word Search II) 给定一个二维网格 board 和一个字典中的单词列表 words,找出所有同时在二维网格和字典中出现的单词. 单 ...

随机推荐

  1. nodeJs常用API

    1.url (1)url.parse返回url对象的各种参数 url.parse(url,true/false,true/false);//默认url.parse(url,false,false); ...

  2. 反向传播BP为什么高效

    之前有一篇文章讲了反向传播的原理: 下面这篇文章讲了反向传播为什么高效: https://blog.csdn.net/lujiandong1/article/details/52716726 主要通过 ...

  3. Sublime Theme

    Package Control Messages======================== Theme - Spacegray----------------- Thanks for insta ...

  4. ssh2学习-applicationContext.xml文件配置-----<context:annotation-config/>详解

    当我们需要使用BeanPostProcessor时,直接在Spring配置文件中定义这些Bean显得比较笨拙,例如: 使用@Autowired注解,必须事先在Spring容器中声明AutowiredA ...

  5. windows 7 提示升级到windows 10补丁

    如果不需要这个提示,可以卸载KB3035583和KB2952664这两个系统更新补丁.   other update:KB2976978   and  KB2977759

  6. JUnit4.8.2源码分析-1 说明

    阅读本系列文章时须要知道的: JUnit是由GOF 之中的一个的Erich Gamma和 Kent Beck 编写的一个开源的单元測试框架,分析JUnit源码的主要目的是学习当中对设计模式的运用.JU ...

  7. AR路由器web界面每IP限速配置方法

    一.做下载方向的限速:在 QOS>接口限速,选择“新建”“接口名称”选择内网接口“限速类型”选择IP限速(目的)“方向”选择流出“起始/目的ip”写内网的ip“类型”选择独占“承诺速率”为限速的 ...

  8. python(30)- 常用模块

    模块就是py文件.python中能开辟作用域的只有函数.类和模块. for循环不能开辟作用域,for循环内的变量为全局变量.if...else...同for循环一样. 一 time模块 时间表示形式 ...

  9. ActiveMQ与MSMQ的异同

    http://www.cnblogs.com/luluping/archive/2010/11/03/1867841.html      目前常用的消息队列组建无非就是MSMQ和ActiveMQ,至于 ...

  10. php中利用reset,current,next和each,list来遍历数组

    1.利用for循环以及reset,current,next来遍历数组: $nums = array(11,22,33,44,55,66,77,88); for(reset($nums);current ...