【本文首发于CSDN个人博客,转载请注明出处。In case of infringement, please contact to delete. 侵删。】
欢迎交流想法!若有错误请指出。P.S. 欢迎【关注&点赞&收藏】哈~
LeetCode 10 - Regular Expression Matching
思路简述
第一次看的时候没思路(看完解答也觉得好难啊,指路https://leetcode.cn/problems/regular-expression-matching/solution/shou-hui-tu-jie-wo-tai-nan-liao-by-hyj8/)。
所以这次总结一下动规相关内容吧 😃
动态规划
1. 什么时候能用动态规划?
动态规划常常适用于有重叠子问题和最优子结构性质的问题,并且记录所有子问题的结果。
数据结构曾经学的DP,我的印象中就是把后面可能用到的中间内容存下来,方面使用时直接读取。即,当每个阶段的最优状态可以从之前某个阶段的某个或者某些状态直接得到,而不管之前这个状态是如何得到的(注意和贪心算法区别在于,贪心要求每步由上一步最优解得出)。
- 重叠子问题
在不停分解原问题的时候,要保证分解的子问题越小,重叠性越大【不同情况下的原问题在分解过程中,会指向相似/相同的子问题】。
- 最优子结构性质
一个问题的最优解包含其子问题的最优解,即保证子问题最优解就能保证该问题得到最优解【在强化限制条件的时候,缩小问题解决范围】。
- 无后效性
“未来与过去无关”。一旦确定某阶段结果,后面该状态下最优解不再变化。
2. 问题可能展现情况
1)极值问题
求最大/最小。e.g. LeetCode 5 - Longest Palindromic Substring .
2)计数、找路径问题
e.g. LeetCode 62 - Unique Paths .
3)求存在性问题
e.g. 本题 LeetCode 10 - Regular Expression Matching(太难了 😦 );
LeetCode 416 - Partition Equal Subset Sum .
3. DP具体怎么写?
两种解法:自顶向下(记忆化递归),自底向上(递推)。
- 前者:
优点:不用重新考虑状态之间的依赖关系,在分治代码的基础上简单改动即可。只有需要用到某个状态才会计算,不会计算无用状态。
缺点:无用状态不多或没有时,比递推开销大,运行慢。
- 后者:
缺点:有时候状态之间的依赖关系不明显。可能会计算到无用状态。
如何选择?
有些题目只能用记忆化搜索,有些题目只能用递推。
有些题目这两种形式都可以用,选择方法如下:
1)当无用状态多的时候,用记忆化搜索。
2)当无用状态不多,依赖关系明显的时候,用递推。
3)以上两种都不是的时候,优先选择记忆化搜索。
另外,计数、求和的问题,状态转移方程的一般形式是相加;对于求最值问题,状态转移方程的一般形式是从两个状态中取最大或最小的那个;对于求存在性问题,状态转移方程的一般形式是直接赋值。
总之,先用边界条件定性,再实现转移方程。
[参考] 指路 https://blog.csdn.net/weixin_45738899/article/details/121566578
https://blog.csdn.net/xingjingb/article/details/118660746