# 1.2 Dynamic Programming Framework
## 1.2.0 intro:
- 一般形式: 求極值
- 核心問題: 列舉
- 思考如何列舉所有結果
- 存在"重疊子問題" (Overlapping sub-problems)--> Memo
- 具備"最佳子結構" (optimal sub-structure)
- 列出正確的"狀態轉移方程"-->state transfer function, most difficult
- 思考要點:
- base case (最簡單的情況)是什麼?
- 這個問題有什麼"狀態"?
- 對於每個"狀態",可以做出什麼"選擇",使得"狀態"發生改變?
- 如何定義dp陣列/函數的涵義,以便表現"狀態"和"選擇"?
- 三點: 狀態、選擇、dp陣列的定義
~~~
# initialize base case
dp[0][0][...] = base case
for state1 in all possible:
for state 2 in all possible:
dp[state1][state2] = max/min(option 1, option 2)
~~~
## 1.2.1 Fib sequence for overlapping sub-problems
~~~
int fib(int N){
if (N==0) return 0;
if (N==1 || N==2) return 1:
return fib(N-1)+ fib(N-2);
}
~~~
- Complexity of Recursive = # of sub-problems x complexity of sub-problem
- Fib (Brute Force) : O($2^n$)
- DP Optimization for overlapping sub-problems:
- First, write a brute-force version (include state transfer function)
- Choose method:
- Memo (Top-down)
- dp table: (Bottom-up)
- (Advanced) State compressiong: Based on state-transfer-function, there might be method to reduce dp table to save spce complexity.
## 1.2.2 Coin change: State transfer function (optimal sub-structure)
- Problem: given k types of coins (c1,c2,...,ck), and target amount-->min # of coins
- Steps:
- Base case: amount = 0--> return 0
- 確定"State": 原本問題與子問題的變數(e.g., amount)
- 確定"選擇": 導致狀態改變的行為
- 明確dp: 函數/ 陣列定義
- dp"函數"的狀態體現於"函數參數"
- dp"陣列"的狀態體現於"陣列索引"
- Top Down (Memo)
~~~ python
def coinChange(self, coins, amount):
memo = dict()
def dp(n):
# Memo
if n in memo: return memo[n]
# base case
if n==0: return 0
if n<0: return -1
res = float('INF')
# state transfer
for coin in coins:
subproblem = dp(n-coin)
if subproblem==-1: continue
res = min(res, 1+subproblem)
# add into memo
memo[n]= res if res!=float('INF') else -1
return memo[n]
return dp(amount)
~~~
- Bottom Up (DP table)
~~~C++
int coinChange(vector<int>& coins, int amount){
// size of array = amount+1
// initialized value = amount +1 (like an infinite value)
vector<int> dp(amount+1, amount+1);
// base case
dp[0]=0;
// for All the states
for(int i = 0;i<dp.size();i++){
// for all the options
for(int coin : coins){
// if sub-problem is not sovlable, by pass it.
if (i-coin<0) continue;
// solve sub-problem.
dp[i]=min(dp[i], 1+dp[i-coin]);
}
}
return (dp[amount]==amount+1)? -1: dp[amount];
}
~~~