从暴力递归到动态规划
Last updated
Last updated
从代码角度, 动态规划的实现一般都是通过迭代完成的 (递推公式); 而一般迭代过程都有与之对应的递归写法;
这里默认动态规划都是基于迭代的实现. 实际上, 动态规划只是一种算法, 跟具体实现无关, 递归实现也是动态规划;
递归过程一般与人的直接思考过程更接近, 因此如果对递归结构比较熟悉, 就能更容易的写出相应解法;
动态规划的难点是递推过程 (经验和数学能力); 递归的难点是递归结构本身;
递归的一个问题是如果存在重复计算, 会大幅降低性能, 此时有两个解决方法:
转换为迭代结构; 转化过程可以套用固定模板, 详见示例;
使用记忆化搜索, 即保存中间结果; 如果用 python 书写, 可以使用 functools.lru_cache
装饰器, 详见示例;
如何判断是否存在重复计算?
将递归过程展开为树状结构,当发现某些具有相同参数的递归调用出现在多个不同节点时,说明存在重复调用;
什么情况下可以使用记忆化搜索?
这个问题的本质, 实际上是判断问题本身是不是一个动态规划问题; 能用动态规划解决的问题必须具备无后效性, 只要具备这个特性, 就可以使用记忆化搜索;
无后效性: 某阶段的状态一旦确定, 则此后过程的决策不再受此前各种状态及决策的影响.
原文总结了 4 种常见的递归过程,基本能覆盖大部分场景;
最常见的递归模型, 一般过程:
确定初始状态 (递归基), 即 $k=0$ 时刻的状态)
假设已知 $k-1$ 及其之前时刻的状态,推导 $k$ 时刻的状态;
有时候可能是自顶向下, 本质是一样的;
该模型下的一维问题几乎都是 "跳台阶" 问题的变体;
有限制的 "跳台阶" 问题;
进阶版 "跳台阶", 相当于每次能跳的步数更多;
该类型原文只给了很难的几个例子, 感兴趣的可以去看原视频;
algorithms/暴力递归与动态规划