遞迴問題
暴力遞迴轉換成動態規劃
動態規劃本身就是暴力遞迴的優化,是一種用空間換時間的策略
動態規劃:
我們不知道怎麼計算n!
,但我們知道:
n!
與(n-1)!
之間存在一定關係n!=n*(n-1)!
,得到遞推的狀態轉移公式
.
當暴力遞迴到頭得到0!=1
,得到base case
,這樣得到了遞迴的方法.
public
static
long
getfactorial1
(int n)
return
(long
) n *
getfactorial1
(n -1)
;}
將遞推反過來考慮,從base case
出發,可以得到遞推方法:
public
static
long
getfactorial2
(int n)
return result;
}
問題: 不能大壓小,只能小壓大,每次只能移動乙個圓盤.最終借助help
堆將n
層圓盤從from
堆移動到to
堆. 列印n層漢諾(最上面為第1層,最下面為第n層)塔從from
移動到to
的全部過程
思路:
先來**將第[1~n]層
從from
移動到to
的過程:
先把第[1~(n-1)]層
從from
移動到help
上.
再把單獨的第n層
移從from
移動到to
上.
再把第[1~n-1]層
從help
移動到到to
上.
這三步中第1步
和第3步
都是將規模縮小了的子問題,這樣得到了狀態轉移公式
.
這裡我們**第[1~n]層
時,大於n層
的所有圓盤都應該在這些盤子以下,因此絕對不會出現小壓大的情況.
下面我們尋找base case
: 容易想到,當漢諾塔只有一層時,可以不借助help
,直接將該層從from
移動到to
由此得到其遞迴**如下:
public
class
hanoi
else
}public
static
void
main
(string[
] args)
}
輸出3層漢諾塔的移動過程如下:
將第1層盤子從左堆移動到中堆
將第2層盤子從左堆移動到右堆
將第1層盤子從中堆移動到右堆
將第3層盤子從左堆移動到中堆
將第1層盤子從右堆移動到左堆
將第2層盤子從右堆移動到中堆
將第1層盤子從左堆移動到中堆
暴力遞迴:
狀態轉移公式
: 對於字串中每個字元每個字元可以選擇要或不要,
base case
: 判斷完最後乙個字串就可以輸出了.
暴力遞迴:
狀態轉移公式
: 每一位的字元都可以跟自己及其後面任意乙個字元
相交換
base case
: 判斷完最後乙個字串就可以輸出了.
暴力遞迴
方法會導致大量狀態被重複計算,而動態規劃通過記憶這些狀態的值,避免了重複計算,是一種用空間換時間
的策略.
有一類問題能從暴力遞迴
轉換為動態規劃
,被稱作無後效性問題
.
問題: 給出乙個二維陣列,要求返回從左上角到右下角的最小路徑和.
暴力遞迴:
設walk(int i, int j)
函式返回某點到右下角的最小路徑和
題目: 給你乙個陣列arr
和乙個整數aim
. 任意選擇arr中的數字,能否累加得到aim.
暴力遞迴: 類似子串行問題,每個數字都可以選擇要或者不要.
issum(判斷到的index, 前邊的累加和sum)
函式返回陣列[0~index]
區間內是否能累加成目標aim
.
狀態轉移方程
: 若[0~index-1]
之間選擇數字能達到aim-arr[index]
,則[0~index]
一定能選擇數字達到aim
; 否則不能達到aim
.即issum(index, sum) = issum(index-1, sum-arr[index])
.
base case
:index=陣列長度
表示判斷完整個陣列的結果,因此判斷其前向累加和
是否為aim
填表. 且不論index
為多少,前向累加和
若為aim
,則返回true.
動態規劃:
設想如下數字序列:,判斷完前三個數字時,是選擇
還是選擇
,前邊的累加和都是一樣的,不影響後邊判斷.
因為從[0~index]
之間選擇具體哪幾個數字達到aim
與 後面選擇無關,因此是乙個無後效性問題
,可以用動態規劃
.
從base case
,即index=len
開始,向index
減小方向遞推,直到遞推到並返回issum(0,0)
.
**如下:
public
static
boolean
money2
(int
arr,
int aim)
// 按判斷的index從arr.length到0遞減填表
for(
int i = arr.length -
1; i >=
0; i--)}
}// 結果應返回: 最開始選擇0個數,且初始累加和為0時的結果
return issum[0]
[0];
}
推廣: 考慮陣列成員存在負數的情況,若陣列成員有負數,則前向累加和可能為負數,因此所填的表的橫座標可能為負數. 實際編碼過程中,給累加和
項加乙個偏移
,偏移量為累加和可能的最小負數.
這類問題與給定兩個陣列w和v,兩個陣列長度相等,w[i]表示第i件商品的重量,v[i]表示第i件商品的價值。 再給定乙個整數bag,要求你挑選商品的重量加起來一定不能超 過bag,返回滿足這個條件下,你能獲得的最大價值。k-sum問題
的區別: k-sum問題為有後效性問題
,因為要求只能選取k
個數,所以在記錄累加和的同時要考慮已經選取了幾個數.
演算法學習 動態規劃
動態規劃是解決多階段決策過程最優化的一種方法。對於離散問題,解析數學無法施展,動態規劃則成為非常有效的工具。兩個弱點 1.得出目標函式方程後,尚無統一的處理方法,必須根據具體問題的性質結合相應的數學技巧來求解 2.維數障礙。動態規劃模型的分類 根據決策過程的時間參量是離散的還是連續的變數 1.離散 ...
演算法學習 動態規劃實踐
完成日期 2017.10.26 1.實踐題目 數字三角形 2.問題描述 給定乙個由 n行數字組成的數字三角形如下圖所示。試設計乙個演算法,計算出從三角形 的頂至底的一條路徑 每一步可沿左斜線向下或右斜線向下 使該路徑經過的數字總和最大。3.演算法描述 1 首先該問題有最優子結構和重疊子問題的性質,因...
演算法學習(十)動態規劃!!!
1.先上一波官方解讀提提神 動態規劃 英語 dynamic programming,簡稱dp 是一種在數學 管理科學 電腦科學 經濟學和生物資訊學中使用的,通過把原問題分解為相對簡單的子問題的方式求解複雜問題的方法。動態規劃常常適用於有重疊子問題和最優子結構性質的問題。官方術語太多?不能理解?wha...