博客
关于我
算法笔记:递归、动态规划
阅读量:417 次
发布时间:2019-03-06

本文共 2338 字,大约阅读时间需要 7 分钟。

目录

动态规划是求解决策过程最优化的过程,可以高效求解那些可以分解为高度重复子问题的问题,应用非常广泛,比如解决最短路线、NLP等实际问题。

递归、分治和动态规划

德罗斯特效应

德罗斯特效应(Droste effect)是递归艺术中的一种表现形式,德罗斯特效应即在一幅图像中,某个局部图像与整体图像类似,而在这个局部中,又有更小的部分与这个局部类似,依次类推且可无限重复。

德罗斯特(Droste)可可粉的包装盒

德罗斯特是荷兰的一个著名巧克力品牌,创立于1863年,上面这张图片从1904年起开始使用,数十年间只进行了一些小幅的调整,后来成为一个家喻户晓的概念。诗人及专栏作家Nico Scheepmaker在七十年代起,开始使用“德罗斯特效应”此一词语。下面介绍动态规划算法。

递归、分治和动态规划

迭代和递归的区别

  • 迭代是将输出作为输入,再次进行处理。
  • 递归,自己调用自己,自己包含自己。

分治

分治( Divide &Conquer )是将问题分解为若干个子问题(Divide),递归求解这些子问题(Conquer),然后合并子问题的解。

动态规划

动态规划(Dynamic Programming)和分治策略类似,也是将原问题分解为若干子问题,递归的求解这些子问题,然后合并子问题的解得到原问题的解。

通常许多子问题非常相似,为此动态规划法试图仅仅解决每个子问题一次,从而减少计算量:一旦某个给定子问题的解已经算出,则将其记忆化存储,以便下次需要同一个子问题解之时直接查表。这种做法在重复子问题的数目关于输入的规模呈指数增长时特别有用。(维基百科:)

通常许多子问题非常相似,为此动态规划法试图仅仅解决每个子问题一次,从而减少计算量。动态规划、递归和分治没有根本上的区别,解法都是先找到重复的子问题,也就是将问题拆解成可重复解决的问题。

解法

递归问题解法:

  1. 找到重复子问题
  2. 确定递归终止条件

对于动态规划问题,每个子问题只求解一次,注意将其结果保存起来,进行记忆化存储。

斐波那契数

斐波那契数列LeetCode地址:

解法1:暴力递归

class Solution:    def fib(self, n):        if n <= 0:            return 0        elif n == 1:            return 1        else:            return self.fib(n - 1) + self.fib(n - 2)if __name__ == "__main__":    solu = Solution()    result = solu.fib(6)    print(result)

结果:

8

时间复杂度:O(2^N)

空间复杂度:O(N)

如果数比较大,2^N的时间复杂度将会占用大量资源,计算非常慢。其实暴力递归计算过程中,进行了大量重复计算,我们来看一下Fib(6)的状态树:

我们发现f(4)计算了2次,f(3)计算了3次,其实没必要重复计算,可以使用记忆化存储来保存计算值。

解法2:记忆化存储

class Solution:    def fib(self, n):        cash = {0:0,1:1}        def memoize(n):            if n in cash:                return cash[n]            cash[n] = memoize(n - 1) + memoize(n - 2)            return cash[n]        return memoize(n)if __name__ == "__main__":    solu = Solution()    result = solu.fib(6)    print(result)

时间复杂度:O(N)

空间复杂度:O(N)

解法3:动态规划

class Solution:     def fib(self, n):         if n <= 1: return n        dp = [0, 1] + [0]*(n-1)        for i in range(2, n+1):            dp[i] = dp[i-1] + dp[i-2]        return dp[i]        if __name__ == "__main__":    solu = Solution()     result = solu.fib(6)     print(result)

时间复杂度:O(N)

空间复杂度:O(N)

解法4:自底向上迭代

可以进一步减少空间复杂度

class Solution:     def fib(self, n):         if n <= 1: return n        a, b = 0, 1                for _ in range(1, n):            c = a + b            a, b = b, c        return c        if __name__ == "__main__":     solu = Solution()     result = solu.fib(6)     print(result)

时间复杂度:O(N)

空间复杂度:O(1)

--THE END--

欢迎关注公众号:「测试开发小记」及时接收最新技术文章!

转载地址:http://sxouz.baihongyu.com/

你可能感兴趣的文章
Dubbo 的心跳设计,值得学习!
查看>>
送给你 12 个 Git 使用技巧!
查看>>
国人开源了一款超好用的 Redis 客户端,真香!!
查看>>
盘点 100 个最受欢迎的 Java 库!谁拔得头筹?
查看>>
使用 Redis 实现一个轻量级的搜索引擎,牛逼!
查看>>
你还在用分页?试试 MyBatis 流式查询,真心强大!
查看>>
如何写出让同事无法维护的代码?
查看>>
查看 JVM 内存的几个工具,建议收藏!
查看>>
每天数十亿次请求的应用经验分享,值得参考!
查看>>
推荐一款 ES 集群可视化工具:Cerebro,简单、实用!
查看>>
Spring 双层事务,我抛出的异常去哪了?
查看>>
一个 Java 对象到底有多大?
查看>>
你还在用命令看日志?快用 Kibana 吧,一张图片胜过千万行日志!
查看>>
Spring Boot 老启动失败,这次再也不怕了!
查看>>
Spring Boot 配置加载顺序详解
查看>>
Java 11 正式发布,这 8 个逆天新特性教你写出更牛逼的代码
查看>>
史上最全 40 道 Dubbo 面试题及答案,看完碾压面试官!
查看>>
怎么写一个带名字滚动的抽奖页面
查看>>
python进阶(3)json文件与python字典的转化
查看>>
python进阶(7)垃圾回收机制
查看>>