专栏名称: 每日一道算法题
学习算法是一种信仰,每天都需要坚持!
目录
相关文章推荐
九章算法  ·  又一个方向,被转码带火了! ·  2 天前  
九章算法  ·  被裁6个月,躺平6个月,上岸! ·  3 天前  
九章算法  ·  这可能是码农新一次财富分配的机会…… ·  2 天前  
新机器视觉  ·  一文了解强化学习 ·  5 天前  
九章算法  ·  准Meta E5的最后一舞 ·  1 周前  
51好读  ›  专栏  ›  每日一道算法题

[每日一题]DP小结一:重叠子问题

每日一道算法题  · 公众号  · 算法  · 2017-04-24 22:36

正文

导读


如下是我关于 动态规划 的理解,有理解不到位的地方欢迎指正!一起讨论,争取大家一起攻克动态规划的难题。


今天的题目是 70. Climbing Stairs

You are climbing a stair case. It takes 

You are climbing a stair case. It takes n steps to reach to the top.


https://leetcode.com/problems/climbing-stairs/#/description


这道题其实是一道求 斐波拉契数列的题。斐波拉契数列是动态规划的经典题,题目不难但可以考察到动态规划的很多方面。所以非常适合通过斐波拉契数列来理解动态规划。

是什么


动态规划思想是将一个复杂的问题转换成多个子问题,并且存储子问题的处理结果。


一般情况下,我们求最优解都是遍历所有的可行方案,最后选择最符合要求的结果。但当数据量比较大的时候,穷举方案不可行。这个时候,就需要考虑使用动态规划来解决这类问题。


动态规划有如下几个特性:

  1. 有重叠的子问题

  2. 具有最优子结构

  3. 无后效性

有什么

重叠子问题

本质上,就是在求解的过程中有重复计算。下图表示的求 斐波拉契数列的第 5 个元素的值。假设 f(n) 表示 斐波拉契数列第 n 个元素的值,那么 f(5) = f(5-1) + f(5-2) = f(4) + f(3), f(4) = f(3) + f(2)  其中 f(3) 计算了两次。也就是说在求 f(5) 的过程中,至少有一个重复的计算 f(3) ,而f(3) 的求解就是全局解的重叠子问题。

重复计算的解题方案有两个:

  1. 自顶向下的记忆优化

  2. 自底向上的表格方案


自顶向下的记忆优化


先看一下纯的 DFS 的解法



记忆优化是基于 DFS版本来做的:在 DFS 的基础上,缓存下节点的值。


在第一次深度遍历的时候,我们把遍历的每次结果都缓存到起来(可以用数组或者Hash存储缓存)。在第二次遍历的时候,就不需要重复计算,直接在缓存中取结果就可以了。这样有效的降低算法的时间复杂度。



自底向上的表格方案
该方案就是从叶子节开始求解,并且用一个 Table 缓存下所有的求解的值。

先求 f(1) 得值,然后求 f(2) , f(3) ... f(n) ,并在求解的过程中,将f(x) 的值缓存到一个 数组或者表格中。


上面的解题方案的空间复杂度是 O(N) ,其中大部分空间都是浪费的。因为 n 的值至于 n - 1 和 n - 2 相关,其中 1 到 n - 3 的值不需要一直保存着。所以,本解题方案还可以继续优化:通过滚动数组的技巧将空间复杂度减少到O(1)。


总结


今天总结了重叠子问题相关的知识点。明天总结最优子结构和无后效性的相关知识点。