【LeetCode解题总结】动态规划篇

基本概念

定义

动态规划既是一种数学优化的方法,同时也是编程的方法。

  • 从数学的角度看,动态规划要解决的都是问题的最优解。而一个问题的最优解是由它的各个子问题的最优解决定的。(最优子结构)
  • 从编程的角度看,动态规划可以借助编程的技巧去保证每个重叠的子问题只会被求解一次。(重叠子问题)

难点

  • 应当采用什么样的数据结构来保存什么样的计算结果
  • 如何利用保存下来的计算结果推导出状态转移方程

第一个难点,不仅是为了避免重复的计算,也是推导状态转移方程的关键。这一难点往往是在把问题规模缩小的过程中进行的。

解决技巧:假设已经把所有子问题的最佳结果都计算出来了,那么只需要考虑,如何根据这些子问题的结果来得出最终的答案。

解法总结

线性规划

线性,就是说各个子问题的规模以线性的方式分布,并且子问题的最佳状态或结果可以存储在一维线性的数据结构里,例如一维数组,哈希表等。

解法中,经常会用 dp[i] 去表示第 i 个位置的结果,或者从 0 开始到第 i 个位置为止的最佳状态或结果。例如,最长上升子序列。dp[i] 表示从数组第 0 个元素开始到第i个元素为止的最长的上升子序列。

求解 dp[i] 的复杂程度取决于题目的要求,但是基本上有两种形式。

求解 dp[i] 形式一

第一种形式,当前所求的值仅仅依赖于有限个先前计算好的值,也就是说,dp[i] 仅仅依赖于有限个 dp[j],其中 j < i。

举例:求解斐波那契数列

解法:dp[i]=dp[i−1] + dp[i−2],可以看到,当前值只依赖于前面两个计算好的值。

求解dp[i]形式二

第二种求解 dp[i] 的形式,当前所求的值依赖于所有先前计算好的值,也就是说,dp[i] 是各个 dp[j] 的某种组合,其中 j 由 0 遍历到 i−1。

举例:求解最长上升子序列。

解法:dp[i]=max(dp[j]) + 1,0 <= j < i。可以看到,当前值依赖于前面所有计算好的值。

区间规划

区间规划,就是说各个子问题的规模由不同的区间来定义,一般子问题的最佳状态或结果存储在二维数组里。一般用 dp[i][j] 代表从第 i 个位置到第 j 个位置之间的最佳状态或结果。

解这类问题的时间复杂度一般为多项式时间,对于一个大小为 n 的问题,时间复杂度不会超过 n 的多项式倍数。例如,O(n)=n^k,k 是一个常数,根据题目的不同而定。

举例:最长回文子串

约束规划

在普通的线性规划和区间规划里,一般题目有两种需求:统计和最优解。

这些题目不会对输出结果中的元素有什么限制,只要满足最终的一个条件就好了。但是在很多情况下,题目会对输出结果的元素添加一定的限制或约束条件,增加了解题的难度。

举例:0-1 背包问题

技巧

  • 线性规划和区间规划可以考虑画图来确定计算顺序和优化内存
原文地址:https://www.cnblogs.com/JasonBUPT/p/11868558.html