對於換零錢問題,最簡單也是性能最好的方法就是貪心算法。但是貪心算法必定要知足面值相鄰兩個零錢至少爲二倍關係的前提條件。例如1,2,5,10,20……這樣的零錢組應用貪心最簡單;可對於1,3,4,5,6,10……這樣的零錢組就不起效了:當目標總值是12的時候,應用貪心算法:答案是10x1+1x2,共3張,可正確答案應該是6x2共兩張。程序員
那怎麼解決呢?這樣的問題符合動態規劃的特色:任何一個狀態能夠由前邊的狀態計算而得。算法
定義問題(明確需求):一組不重複且升序排列零錢面額數組vector<int> c(共m個元素),目標面值:int n,求所需最少的零錢張數。數組
就像揹包問題。最經典的算法是生成一個(m+1)x(n+1)DP數組來保存中間值,其中dp[i][j]表示只利用第1~i種零錢湊成目標面值爲j所需的最少零錢張數。性能
咱們很容易得出狀態轉移方程:優化
dp[i][j]=min(0+dp[i-1][j],1+dp[i-1][j-1*c[i]],2+dp[i-1][j-2*c[i]], ······);程序
從而很容易寫出代碼。方法
但做爲一個追(xian)求(de)卓(dan)越(teng)的程序員,我又怎麼會知足於此?看起來時間複雜度O(mn)已經達到極至,可空間複雜度O(mn)好像能夠繼續優化!總結
由上邊的狀態轉移方程,咱們發現每一個元素只用到了上一行的若干個元素。那其實咱們很容易想到,一個大小爲2*(n+1)的一維數組就足夠了!動態規劃
狀態轉移方程:時間
dp[index][j]=min(0+dp[1-index][j],1+dp[1-index][j-1*c[i]],2+dp[1-index][j-2*c[i]], ······);
計算方法沒有任何差異,可是空間複雜度卻大大下降!
不只如此,對於有一些DP算法,每一個元素的計算只須要用到當前行左邊的元素和上一行相同列座標元素的值(例如矩陣的最小最徑的DP算法),這樣的算法,咱們能夠直接用一個n+1的一維數組做爲DP數組就夠用了!
由此,咱們能夠總結出本文的中心思想:
(1)一個二維DP算法,若是每一個元素的計算只須要用到上一行的若干個元素的值的時候,咱們均可以用兩個一維DP數組來優化空間複雜度。
(2)一個二維DP算法,若是每一個元素的計算只須要用到當前行左邊的元素和上一行相同列座標元素的值的時候,咱們均可以用一個一維DP數組來優化空間複雜度。
(3)要多嘗試下降二維DP算法的空間複雜度。
鼓掌[逃]!