总结自《左程云算法教程》(P50-P55)
- 任何动态规划过程都可以从相应的暴力递归过程转化而来;
这里的递归一般指的是自底向上的递归(二叉树的后序遍历);
- 为什么不直接动态规划,而要先考虑暴力递归?
为了避免直接思考递推过程——动态规划的主要难点是递推过程,如果没有足够的经验或者数学敏感性,想要直接找出递推过程的难度很大;而递归过程与直觉非常接近,一般来说,只要能解释清楚递归的输入和输出是什么,就能按照描述写出递归过程(虽然这也需要大量的练习,但这里的难点主要来源于代码结构,而不是数学能力)
- 如何将暴力递归转动态规划?
当得到暴力递归过程后,就可以直接按部就班将其改写为动态规划,这个改写的过程已经将动态规划与原问题解耦(照着递归过程填空即可);
详见示例问题(非常直观)
- 什么情况下,才需要将递归转化为动态规划?
并不是所有递归都需要转动态规划的,只有当递归过程中存在大量重复计算时才需要;
- 如何判断是否存在重复计算?
一般来说,递归过程都可以展开成某个树状结构,在展开过程中,当发现某些具有相同参数的递归调用出现在多个不同节点下时,说明存在重复调用;
以斐波那契数列为例: f(5) f(4) f(3) f(3) f(2) ... 可以看到,f(3) 同时出现在了 f(5) 和 f(4) 的节点下
- 根据以上结论,可以将求解动态规划的过程,转变为求解更简单的暴力递归过程;
- 下面总结了四类常见的递归过程,基本能覆盖大部分场景;
模型不是模板,而是提供了一种思路,它不是死板的套路
形式上就是常见的自底向上递归
自底向上递归的一般过程:
- 确定递归基(
k=n
或k=0
时刻的状态)- 假设已知
k-1
或k+1
时刻的状态,推导k
时刻的状态;相关内容:自底向上的递归技巧
经典问题
- 【简单】跳台阶 - 力扣(LeetCode)
- 【中等】01背包_牛客网
- 【中等】打家劫舍 - 力扣(LeetCode)
- 【中等(三维DP)】一和零 - 力扣(LeetCode)
一般是两个样本
经典问题
- 【困难(中等)】编辑距离 - 力扣(LeetCode)
- 【中等】最长公共子序列 - 力扣(LeetCode)
经典问题
- 【困难】排成一条线的纸牌博弈问题_牛客网
经典问题
以上问题的具体代码详见《暴力递归转动态规划解题合集》