動態規劃(dynamic programming)簡稱DP。
DP系列:
ACM總結——動態規劃(1)重疊子問題、最優子結構
https://blog.csdn.net/nameofcsdn/article/details/106417240
ACM總結——動態規劃(2)問題本身的固有屬性決定數據結構和算法
https://blog.csdn.net/nameofcsdn/article/details/106436743
ACM總結——動態規劃(3)空間壓縮
https://blog.csdn.net/nameofcsdn/article/details/106507259
ACM總結——動態規劃(4)問題的形式化描述
https://blog.csdn.net/nameofcsdn/article/details/106497777
ACM總結——動態規劃(5)二維DP
https://blog.csdn.net/nameofcsdn/article/details/106559659
先看幾個簡單的問題:
1,斐波那契數列
1,1,2,3,5,8......
求第n項
int fac(int n)
{
if(n<3)return 1;
return fac(n-1)+fac(n-2);
}
時間複雜度O (1.6 ^ n)
遞歸寫法(備忘錄法):
int ans[1000]={0};
int fac(int n)
{
if(n<3)return 1;
if(ans[n])return ans[n];
return ans[n]=fac(n-2)+fac(n-1);
}
非遞歸寫法:
int ans[1000]={0,1,1};
int fac(int n)
{
for(int i=3;i<=n;i++)ans[i]=ans[i-1]+ans[i-2];
return ans[n];
}
遞歸寫法不需要控制DP的計算順序,非遞歸寫法需要嚴格控制計算順序。
讀者可此處思考一下上述遞歸寫法的實際計算順序,假設編譯器是默認先執行加法左邊的,再執行加法右邊的。
兩種寫法的時間複雜度都是O(n)
爲什麼差異這麼大?
這就是DP的第一個重要特性:重疊子問題
2,求數列中位數
這個題,能不能像上一題這麼做呢?
如果我用f(n)表示數列前n個數的中位數,那麼,由f(n-1)和f(n-2)可以直接推導出f(n)嗎?
不能!
差異在哪?差異在於問題本身的性質不同。
這種由子問題的答案可以直接推導出原問題答案的性質,其實就是最優子結構。
最優子結構:問題的最優解包含了子問題的最優解。
再來看看一個動態規劃的題目,當我們分析它的時候,我們在想些什麼?
3,數列的DP問題
一維
力扣 OJ 300. 最長上升子序列
https://blog.csdn.net/nameofcsdn/article/details/104086350
力扣OJ 1218. 最長定差子序列
https://blog.csdn.net/nameofcsdn/article/details/106418150
二維
力扣 OJ 1143. 最長公共子序列
https://blog.csdn.net/nameofcsdn/article/details/104091938
CSU - 1060 Nearest Sequence (三個數組的最長公共子序列)CSU - 1060 Nearest Sequence (三個數組的最長公共子序列)
https://blog.csdn.net/nameofcsdn/article/details/79697208
4,最短路問題
動態規劃的題目,當我們分析它的時候,主要就是:
問題研究的對象、問題的子問題、最優子結構(即遞推式)、解空間結構
遞歸寫法和非遞歸寫法其實都是解空間的遍歷,而絕大部分問題的解空間都可以映射爲樹空間,樹的遍歷主要就是DFS和BFS,遞歸基本上就是DFS。
什麼是解空間結構?
解空間就是問題可能的解組成的集合,根據問題的屬性,空間的結構也有不同,有的是數組有的是樹等等。
按照問題研究的對象類型和解空間結構,DP問題可以分爲數列DP、區間DP、樹形DP、數位DP、狀態壓縮DP、概率與期望DP、高維DP等等。
DP的更深用法:
空間壓縮、時間優化