【ArchSummit架构师峰会】探讨数据与人工智能相互驱动的关系>>> 了解详情
写点什么

递归算法的时间复杂度

  • 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:29653

评论

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

面试官:说说电商系统订单超时自动取消怎么实现?你有几种方案?

程序员小毕

程序员 面试 程序人生 后端 架构师

可视化:如何选择数据可视化图表?

2D3D前端可视化开发

数据可视化 可视化大屏 可视化图表 可视化工具 sovitchart

数字先锋| 一朵云,将温暖传递千家万户

天翼云开发者社区

数字产业化的颠覆创新和生态打法

PMO实践

产业数字化 11月月更

通过飞书审批 Bytebase 工单

Bytebase

数据库 sql DevOps SQL审核 SQL审批

云原生主题学习月|共同学习全球领先的亚马逊云科技云原生课程,组团共学拿奖励~

亚马逊云科技 (Amazon Web Services)

云原生 培训与认证

Neo4j CEO Emil Eifrem 解读图数据平台引领数据库未来十年的发展

Neo4j 图无处不在

neo4j 图数据库 知识图谱 图可视化引擎 图数据

腾讯云原生容器服务发布三大新能力,创新自研技术助力企业降本增效

科技热闻

玩转云端| 数据库安全服务,为数据库资产构建“最后一道防线”!

天翼云开发者社区

企业内部统一的移动平台,实现安全高效的业务移动化

WorkPlus

老板让我在Linux中使用traceroute排查服务器网络问题,幸好我收藏了这篇文章!

wljslmz

Linux 网络故障 11月月更 traceroute

瓴羊Quick BI在商业智能BI发展趋势方面如何?

对不起该用户已成仙‖

云原生主题学习月|成为社区领学员,解锁专属奖励及超多数量社区学员奖品!

亚马逊云科技 (Amazon Web Services)

云原生 培训与认证

深究用户模式锁的使用场景(异变结构、互锁、旋转锁)

C++后台开发

数据结构 多线程 linux开发 C++开发

焱融科技为国家重点实验室打造海量高性能存储

焱融科技

云计算 分布式系统 高性能 文件存储

企业数字营销和运营如何效果更好?瓴羊Quick BI成为了不错的选择

小偏执o

在结构效率不变情况下的降本增效

PMO实践

数字化转型 数字化 数智化 11月月更

嘉为科技宋蕴真:观测不止于监控,让运维不开盲盒

嘉为蓝鲸

运维 智能运维AIOps

蓝鲸研运体系在腾讯内是如何应用实践的?

嘉为蓝鲸

运维 智能运维AIOps

对话Neo4j首席科学家Jim Webber:图数据库江湖5年后将尘埃落定

Neo4j 图无处不在

neo4j 图数据库 知识图谱 非关系型数据库 图技术

2023 重学 Angular

PingCode研发中心

前端框架

APP以监听投广?中央APP治理专项组测评揭晓答案!

科技热闻

天翼云混合云容灾技术解析

天翼云开发者社区

图数据技术护航网络安全

Neo4j 图无处不在

网络安全 neo4j 图数据库 知识图谱 图算法

互联网企业面试必问Spring源码?搞定Spring源码,看完这篇就够了

钟奕礼

Java java面试 java编程 程序员‘

新时代冠军企业成功硬道理:人效管理与可组装式HCM SaaS

ToB行业头条

微服务治理的3种方式

穿过生命散发芬芳

微服务治理 11月月更

生活中常见的新北洋打印机:多场景赋能美好生活

科技热闻

嘉为科技吴文豪:重塑运维系统,跨越烟囱式建设的陷阱

嘉为蓝鲸

运维 #WeOps

天翼云Serverless边缘容器下沉服务 促进企业聚焦业务创新

天翼云开发者社区

制造业的敏捷分析,还需要使用瓴羊Quick BI

对不起该用户已成仙‖

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