写点什么

递归算法的时间复杂度

  • 2020-02-12
  • 本文字数:12183 字

    阅读完需:约 40 分钟

递归算法的时间复杂度

递归算法大家应该都不陌生吧,其实最开始遇见递归应该是在数学课上,类似于 f(x)=f(x-1)+f(x+1),f(1)=1,f(2)=4,f(3)=3 这种数学题大家应该见过不少,其实思想就是层层递归,最终将目标值用 f(1),f(2),f(3)表示。


之前做个一个需求,需要实现类似操作系统文件夹的功能,我们用 MySQL 数据库记录数据,表字段有 4 列,分别是 id,index_name,pid,is_directory,index_name 记录文件或文件的名字,pid 记录它的父级 id,is_directory 标记它是文件还是文件夹。记录被存下以后,就涉及到取数据的问题了,我们前端需要的目标数据结构是这样的


col 1 | col 2 ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- 1


                2
3 | `[{``"id"``:1,``"name"``:``"./"``},{``"id"``:2,``"name"``:``"./1.txt"``},`
`{``"id"``:3,``"name"``:``"./dir1/"``},`
`{``"id"``:4,``"name"``:``"./dir1/2.txt"``},...]`
有点类似linux系统的tree命令。 </section> </section> </section></section>
复制代码


第一版代码是这样的:


            </section>        </section>
<section> <section> col 1 | col 2 ----------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 | `tree = []`
`def getTree(pid):`
` ``return`
`for` `index ``in` `childIndexes:`
` ``if` `len(tree) == 0:`
` ``if` `index.is_directory==1 tree.append(`
`{``'id'``:index.``id``,``'name'``:``'./'``+index.index_name+``'/'``}) `
`getTree(index.``id``)`
` ``else``: `
`tree.append(`
`{``'id'``:index.``id``,``'name'``:``'/'``+index.index_name})`
` ``else``: `
` ``for` `item ``in` `tree: `
`if` `item[``'id'``] == index.``id`
` ``if` `item.is_directory==1: tree.append({``'id'``:index.``id``,``'name'``: `
`item[``'name'``]+index.index_name+``'/'``}) `
` ``else``: `
` ``tree.append`
`(`
`{``'id'``:index.``id``,``'name'``:item[``'name'``]+index.index_name`
`}`
`)` </section> </section> </section></section>
复制代码


大概看一下这个算法的时间复杂度,第一层的遍历时间复杂度是 n,第二层遍历的时间复杂度是 n,内层的时间复杂度是 O(n^2),再加上递归,最后的时间复杂度是 O(2^n*n^2),这个算法可见很粗糙,假如递归深度到是 100,最后执行效率简直会让人头皮发麻。接下来我们考虑一下如何优化。


第二版代码:


col 1 | col 2 ------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 1


                2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 | `tree = []`
`def getTree(pid,path=``'./'``):`
` ``return`
` ``for` `index ``in` `childIndexes:`
` ``if` `len(tree) == 0: `
` ``if` `index.is_directory==1 tree.append({``'id'``:index.``id``,`
`'name'``:path+index.index_name+``'/'``}) `
` ``getTree(index.``id``, `
`path+index.index_name+``'/'``)`
` ``else``:`
` ``tree.append({``'id'``:index.``id``,`
`'name'``:path+index.index_name}) `
` ``else``: `
` ``if` `item.is_directory==1: tree.append({``'id'``:index.``id``,`
`'name'``:path+index.index_name+``'/'``})`
` ``else``: `
` ``tree.append({``'id'``:index.``id``,`
`'name'``:path+index.index_name})`

</section> </section>
<section> <section></section> </section> </section></section>
复制代码


我们用变量保存每一次的 path,这次我们看看时间复杂度是多少。第一层遍历时间复杂度是 O(n),加上递归,最后的时间复杂度是 O(2^n*n),不算太理想,最起码比第一次好点。


再看看一个面试的常见的题目,斐波拉契数列,n=1,1,3,5,8,13…,求第 n 位是多少?


一看首先就想到了递归的方式:


            </section>        </section>    </section></section>
复制代码


col 1col 2


1


2


3


4 | def fibSquence(n):


``if n ``in (1,2):


``return


``fibSquence(n-1)+ fibSquence(n-2)


这个算法的时间复杂度是 O(2^n),关于时间复杂度具体看调用次数便能明白。我们考虑一下如何优化,比如求 n=3 是,需要先求 n=2,n=1,但是最开始 n=1,n=2 已经求过,多了两步重复计算。


下面是优化的代码:


            </section>        </section>
<section> <section> col 1 | col 2 ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 1
2
3
4
5 | `fibMap = {1:1,2:2}`
`def fibSquence(n):`
` ``else``:`
` ``result = fibSquence(n-1)+ fibSquence(n-2) fibMap.update({n:result})`
` ``return` `result` </section> </section> </section></section>
复制代码


我们用 map 报存中间值,map 是基于 hash 实现的,时间复杂度是 O(1),这样这个算法的时间复杂度就是 O(n)。


但是事实上这个问题大可不必用递归方式求解


            </section>        </section>
<section> <section> col 1 | col 2 ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 1
2
3
4
5
6 | `fibMap = {1:1,2:2}`
`def fibSquence(n):`
` ``else``:`
` ``for` `i ``in` `range(3,n+1): `
` ``fibMap.update({i:fibMap[i-1]+fibMap[i-2]})`
` ``return` `fibMap[n]` </section> </section> </section></section>
复制代码


这样我们只用一次遍历,便可以求出目标值。


递归算法的优化大概就是避免重复运算,将中金状态保存起来,以便下次使用,从结构上来看,是将时间复杂度转换为空间复杂度来解决。递归算法的效率其实是非常低的,能不用递归就尽量不用递归;当然了也要具体问题具体对待,比如说开始提到我做的项目遇到的问题,不用递归我还真想不出其他更好的方式解决。


本文转载自宜信技术学院网站。


原文链接:http://college.creditease.cn/detail/189


2020-02-12 15:29753

评论

发布
暂无评论
发现更多内容

2021年网易Java岗面试必问,Java面试手册pdf

Java 程序员 后端

2021Java高级面试题,极客时间vip年卡,看懂这些帮你轻松解决就业问题

Java 程序员 后端

2021大厂Java面试真题集锦,京东健康Java面试

Java 程序员 后端

2021年Java开发者跳槽指南,2021年我们程序员该如何进阶和规划

Java 程序员 后端

2021年大厂Java高级面试题分享,Java高并发秒杀面试题

Java 程序员 后端

2021年百度Java面试真题,面试官老爱问适配器模式与外观模式

Java 程序员 后端

2021一位Java中级程序员的跳槽面经,最全的BAT大厂面试题整理

Java 程序员 后端

2021年京东Java岗面试必问,Java中级程序员面试题

Java 程序员 后端

2021年字节跳动74道高级程序员面试,2021Java面试真题精选干货整理

Java 程序员 后端

2021年最新Java面试精讲,揭秘今年Java春招面试必问问题有哪些

Java 程序员 后端

2021大厂Java开发面试总结+解答,Java基础笔试题大全带答案

Java 程序员 后端

2021年大厂Java面经,Java高并发编程详解pdf下载

Java 程序员 后端

2021年Java岗位BAT大厂面试题知识点小结,挥泪整理面经

Java 程序员 后端

最新阿里P6-P7Java研发岗面经:技能要求+面试真题+经验总结

Java 程序员 面试 阿里

2021年最新Java面试精讲,java开发技术教程,Java简单入门教程

Java 程序员 后端

2021年是意义非凡的一年,架构师带你玩转Redis高性能缓存设计实战

Java 程序员 后端

2021大厂Java开发面试总结+解答,【一步教学,一步到位】

Java 程序员 后端

2021大厂Java社招最全面试题,2021年Java开发者常见面试题

Java 程序员 后端

【AI 全栈 SOTA 综述 】这些你都不知道,怎么敢说会 AI?【语音识别原理 + 实战】

声网

AI 算法 音视频

2021年Java大厂面试分享,漫谈设计模式在Spring框架中的良好实践

Java 程序员 后端

2021年Java面试心得,从理论到实践!

Java 程序员 后端

2021年是意义非凡的一年,差点挂在第四面

Java 程序员 后端

2021年Java常见面试题目,图灵学院诸葛,阿里P7大牛整理

Java 程序员 后端

2021年上半年最接地气的Java面经,2021年Java常见面试题目

Java 程序员 后端

2021年华为Java面经,顺利收获Offer

Java 程序员 后端

谈一谈最小二叉堆的几种操作

Regan Yue

算法 10月月更

2021年春招Java面试题,2021最新腾讯Java面试分享

Java 程序员 后端

2021大厂Java面试经历,Java技术面试常见问题

Java 程序员 后端

阿里亿级长连网关的云原生演进之路

阿里巴巴终端技术

云原生 架构设计 网关 客户端开发

2021年华为Java面经,【面试必备】

Java 程序员 后端

2021年阿里+腾讯+快手offer都已拿到,Java开发环境

Java 程序员 后端

递归算法的时间复杂度_文化 & 方法_杨轶_InfoQ精选文章