递归 - 时间复杂度

在本文中, 我们主要介绍如何分析递归算法程序中的时间复杂度。.
在一个递归程序中, 它的时间复杂度 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. 64个命令,每天一个linux命令目录, shutdown,tee,rcp,

    每天一个linux命令目录 开始详细系统的学习linux常用命令,坚持每天一个命令,所以这个系列为每天一个linux命令.学习的主要参考资料为: 1.<鸟哥的linux私房菜> 2.htt ...

  2. 面试题:判断两个字符串是否互为回环变位(Circular Rotaion)

    题干:   如果字符串 s 中的字符循环移动任意位置之后能够得到另一个字符串 t,那么 s 就被称为 t 的回环变位(circular rotation).   例如,ACTGACG 就是 TGACG ...

  3. http://www.oschina.net/code/snippet_12_13918

    http://www.oschina.net/code/snippet_12_13918

  4. http://www.ablanxue.com/shtml/201411/25904_1.shtml

    http://www.ablanxue.com/shtml/201411/25904_1.shtml

  5. EL表达式介绍(1)

    1. 产生背景: 在MVC体系结构中,JSP页面只是用来显示数据,但JSP脚本中的表达式功能不够强大,它不能直接对隐式对象中某对象的属性进行显示,需要配合 scriptlet才能显示数据,很是麻烦,如 ...

  6. Java笔记6:多态

    一.多态的分类对象的多态性:动物 x = new 猫();函数的多态性:函数重载.重写 二.多态的体现父类的引用指向了自己的子类对象父类的引用也可以接收自己的对象 三.多态的前提必须是类与类之间只有关 ...

  7. jquery怎样获得父级窗体的大小

    方法例如以下: $(window.parent.window).width() 注意: window能够省略.如:$(parent).width(),parent能够有多级,比方:$(parent.p ...

  8. MPTCP 源码分析(五) 接收端窗口值

    简述:      在TCP协议中影响数据发送的三个因素分别为:发送端窗口值.接收端窗口值和拥塞窗口值. 本文主要分析MPTCP中各个子路径对接收端窗口值rcv_wnd的处理.   接收端窗口值的初始化 ...

  9. Unity学习笔记 之 关于 Unity UI 的 Slider 的代码记录

    代码例如以下: using UnityEngine; using System.Collections; //1.引入 UI . using UnityEngine.UI; public class ...

  10. jQuery (样式篇)

    1.$(document).ready 的作用是等页面的文档(document)中的节点都加载完毕后,再执行后续的代码,因为我们在执行代码的时候,可能会依赖页面的某一个元素,我们要确保这个元素真正的的 ...