递归 - 时间复杂度

在本文中, 我们主要介绍如何分析递归算法程序中的时间复杂度。.
在一个递归程序中, 它的时间复杂度 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. redis秒杀系统数据同步(保证不多卖)

    东西不多卖 秒杀系统需要保证东西不多卖,关键是在多个客户端对库存进行减操作时,必须加锁.Redis中的Watch刚好可以实现一点.首先我们需要获取当前库存,只有库存中的食物小于购物车的数目才能对库存进 ...

  2. PostgreSQL配置文件--资源使用(除WAL外)

    2 资源使用(除WAL外) RESOURCE USAGE (except for WAL) 2.1 内存 Memory 2.1.1 shared_buffers 数字型 默认: shared_buff ...

  3. [转载]CodeGear RAD 2007 SP4 最新下载及破解

    CodeGear RAD 2007 SP4 最新下载及破解  SN: 3AKS-S46LXF-5W7LSF-52CN SN: H4DP-YUSNW7-3MB4TK-2BLD (用这个安装才有源码) C ...

  4. vim删除文本文件中末行^M

    ^M字符的来历和作用:在DOS/Windows里,文本文件的换行符为\r\n,而在*nix系统里则为\n,所以DOS/Windows里编辑过的文本文件到了*nix里,每一行都多了个^M.所以^M只是一 ...

  5. Ubuntu(Debian)的aptitude与apt-get的区别和联系

    Ubuntu(Debian)的aptitude与apt-get的区别和联系 aptitude 与 apt-get 一样,是 Debian 及其衍生系统中功能极其强大的包管理工具.与 apt-get 不 ...

  6. Django开发博客(七)——markdown优化

    背景 上一次把markdown集成之后.发现还是有非常多问题. 这次须要做一些优化. 1.markdown与普通文本的差别显示. 2.添加点击量的统计 3.加入名片卡的滑动 版本号相关 操作系统:Ma ...

  7. C语言循环中降低推断——————【Badboy】

    为了让编译器更好地优化循环,应该尽量让循环中降低推断,方法之中的一个是将推断语句整合进表达式.还是这个样例: for (int i = 0; i < 1000*10; i++) { sum += ...

  8. jQuery 文档操作 - insertAfter() ,insertBefore(),after(),before() 方法

    这个方法跟prependTo()和appendTo()不一样的地方在于,一个是仍然插入到元素内部,而insertAfter和insertBefore是插入到元素外部. 这里拿insertBefore来 ...

  9. SSH——增删改的实现一

    在上一节介绍了关于BOS项目底层的查询操作,接下来介绍一下curd里的其他三项操作步骤 一. 取派员添加 利用easyui在staff.jsp页面里构造添加页面(相关JavaBean创建步骤省略) & ...

  10. 灰色预测--matlab&python实现

    function SGrey X0 = input('请输入原始负荷数据:'); %输入原始数据 n = length(X0); %原始n年数据 %累加生成 X1 = zeros(1,n); for ...