数据结构与算法-暴力递归到动态规划
暴力递归
暴力递归设计思路
暴力递归就是尝试
- 把问题转化为规模缩小了的同类问题的子问题
- 有明确的不需要继续进行递归的条件(base case)
- 有当得到了子问题的结果之后的决策过程
- 不记录每一个子问题的解
常见的递归
-
==> 结论: N层汉诺塔问题移动的最优步数: $2^N -1 $ 步
字符串的子串、子序列 & 全排列
子串:必须是连续的
子序列:在原始字符串中从左往右依次拿字符, 可以不连续, 但是相对次序不能乱
全排列:可以打乱顺序
一个字符串,子串个数是$N^2$个,子序列个数是$2^N$ 个,全排列个数是$N!$ 个
-
- 逆序一个栈,不能申请额外的数据结构,只能使用递归函数。
暴力递归的优化
有重复调用同一个子问题的解,这种递归可以优化
如何分析有没有重复解:列出调用过程,可以只列出前几层,有没有重复解,一看便知
记忆化搜索
-
arr是面值数组,其中的值都是正数且没有重复。再给定一个正数aim。
每个值都认为是一种面值,且认为张数是无限的,返回组成aim的方法数。
例如:arr = {1,2},aim = 4方法如下:1+1+1+1、1+1+2、2+2
一共就3种方法,所以返回3
暴力递归和动态规划的关系
- 某一个暴力递归,有解的重复调用,就可以把这个暴力递归优化成动态规划
- 任何动态规划问题,都一定对应着某一个有解的重复调用的暴力递归
- 但不是所有的暴力递归,都一定对应着动态规划
如何找到某个问题的动态规划方式
设计尝试过程的原则
- 每一个可变参数的类型,一定不要比int类型更加复杂
- 原则1可以违反,让类型突破到一维线性结构,那必须是单一可变参数
- 如果发现原则1被违反,但不违反原则2,只需要做到记忆化搜索即可
- 可变参数的个数,能少则少
常见的尝试模型
1. 从左往右的尝试模型
- 把数字翻译成字符串 leetcode M
- 规定1和A对应、2和B对应、3和C对应…那么一个数字字符串比如”111”就可以转化为:
“AAA”、”KA”和”AK”
给定一个只有数字字符组成的字符串str,返回有多少种转化结果
- 规定1和A对应、2和B对应、3和C对应…那么一个数字字符串比如”111”就可以转化为:
- 背包能装下最多的价值
- 给定两个长度都为N的数组weights和values,weights[i]和values[i]分别代表 i号物品的重量和价值。
给定一个正数bag,表示一个载重bag的袋子,装的物品不能超过这个重量。
返回能装下最多的价值是多少?
- 给定两个长度都为N的数组weights和values,weights[i]和values[i]分别代表 i号物品的重量和价值。
2. 范围上的尝试模型
-
给定一个整型数组arr,代表数值不同的纸牌排成一条线,玩家A和玩家B依次拿走每张纸牌,
规定玩家A先拿,玩家B后拿, 但是每个玩家每次只能拿走最左或最右的纸牌,玩家A和玩家B都绝顶聪明。
请返回最后获胜者的分数。
-
在N*N的棋盘上要摆N个皇后,要求任何两个皇后不同行、不同列, 也不在同一条斜线上
给定一个整数n,返回n皇后的摆法有多少种。
n=1,返回1,n=2或3,2皇后和3皇后问题无论怎么摆都不行,返回0;n=8,返回92。
3. 多样本位置全对应的尝试模型(一个样本做行一个样本做列的对应模型)
4. 寻找业务限制的尝试模型
暴力递归到动态规划的套路
- 你已经有了一个不违反原则的暴力递归,而且的确存在解的重复调用
- 找到哪些参数的变化会影响返回值,对每一个列出变化范围
- 参数间的所有的组合数量,意味着表大小
- 记忆化搜索的方法就是傻缓存,非常容易得到
- 规定好严格表的大小,分析位置的依赖顺序,然后从基础填写到最终解
- 对于有枚举行为的决策过程,进一步优化
动态规划的进一步优化
- 空间压缩
- 状态化简
- 动态规划中的四边形不等式优化
相关题目题解
打印n层汉诺塔从最左边移动到最右边的全部过程(非递归)
1 | // Hanoi.class |
打印n层汉诺塔从最左边移动到最右边的全部过程(递归)
1 | // Hanoi.class |
打印一个字符串的全部子序列
1 | // PrintAllSubsquences.class |
打印一个字符串的全部子序列,要求不要出现重复字面值的子序列
1 | // PrintAllSubsquences.class |
打印一个字符串的全部排列
1 | // PrintAllPermutations.class |
打印一个字符串的全部排列,要求不要出现重复的排列
1 | // PrintAllPermutations.class |
递归逆序一个栈
1 | // ReverseStackUsingRecursive.class |
把数字翻译成字符串
1 | // ConvertToLetterString.class |
把数字翻译成字符串-递归改动态规划
1 | // ConvertToLetterString.class |
背包能装下最多的价值
1 | // Knapsack.class |
背包能装下最多的价值-递归改动态规划
1 | // Knapsack.class |
A,B玩家从左右两边拿纸牌,返回最后获胜者的分数
1 | // CardsInLine.class |
A,B玩家从左右两边拿纸牌,返回最后获胜者的分数-递归改动态规划
1 | // CardsInLine.class |
N皇后问题
1 | // NQueens.class |
N皇后问题-递归改动态规划
1 | // NQueens.class |
面值数组组成面值的方法数-张数不限
1 | // CoinsWay.class |
面值数组组成面值的方法数-张数不限-递归改动态规划
1 | // CoinsWay.class |
If the images or anything used in the blog infringe your copyright, please contact me to delete them. Thank you!