演算法Day02 演算法研習指導之動態規劃演算法框架

2021-10-07 13:36:52 字數 3420 閱讀 1814

湊零錢問題總結

動態規劃的應用場景:

動態規劃的核心問題:

動態規劃的窮舉很特殊:

具備最優子結構:這樣才能通過子問題的最值找到原問題的最值

列出正確的狀態轉移方程才能正確地窮舉:因為窮舉出所有可行解並不是一件容易的事

動態規劃三要素:狀態轉移方程思維框架:

int

fib(

int n)

return

fib(n-1)

+fib

(n-2);

}

這是最簡單易懂的直接遞迴的方法,同時也是效率最低的方法,可以通過畫出遞迴樹看出

觀察遞迴樹,分析出演算法低效的原因:

通常使用陣列作為備忘錄,也可以使用hash表作為備忘錄:

int

fib(

int n)

// 備忘錄初始化為0

vector<

int>

memo

(n+1,0

);// 初始化最簡情況

return

helper

(memo, n);}

inthelper

(vector<

int>

& memo,

int n)

// 已經計算過的直接返回

if(memo[n]!=0

) memo[n]

=helper

(memo, n -1)

+helper

(memo, n -2)

;return memo[n]

;}

迭代的動態規劃解法:自底向上

int

fib(

int n)

return dp[n]

;}

dp table和備忘錄的遞迴樹剪枝後的結構很相似,只不過是反過來計算而已.實際上,帶備忘錄的遞迴解法中的備忘錄,最終完成的就是這個dp table.所以帶備忘錄的遞迴演算法和dp陣列的迭代演算法在大部分情況下的演算法效率是相同的

動態規劃最困難的就是寫出狀態轉移方程

int

fib(

int n)

int prev =

1, curr =1;

for(

int i =

3; i <= n; i++

)return curr;

}

對於計算機來說,解決這個問題的方法就是將所有可能的湊硬幣方法都窮舉出來,然後找找看最少需要多少枚硬幣

確定是動態規劃問題後,就要思考如何列出狀態轉移方程:

然後確定dp函式的定義:

然後確定選擇並擇優:最後明確base case:

def

coinchange

(coins: list[

int]

, amount:

int)

:def

dp(n)

:if n==0:

return

0if n <0:

return-1

# 求最小值,所以初始化為正無窮

res =

float

('inf'

)for coin in coins:

subproblem = dp(n - coins)

if subproblem ==-1

:continue

res =

min(res,

1+ subproblem)

return res if res !=

float

('inf'

)else-1

return dp(amount)

;

def

coinchanges

(coins: list[

int]

, amount:

int)

:# 備忘錄

memo =

dict()

defdp

(n):

# 檢視備忘錄,避免重複計算

if n in memo:

return memo[n]

# 如果備忘錄中不存在,則進行計算

if n =0:

return

0if n <0:

return-1

# 求最小值,所以初始化為正無窮

res =

float

('inf'

)for coin in coins:

subproblem = dep(n - coin)

if subproblem ==-1

:continue

res =

min(res,

1+ subproblem)

# 將計算結果記入備忘錄

memo[n]

= res if res !=

float

('inf'

)else-1

return memo[n]

return dep(amount)

int

coinchanges

(vector<

int> coins,

int amount)

dp[i]

=min

(dp[i],1

+ dp[i - coin])}

}return

(dp[amount]

== dp[amount +1]

)?-1

: dp[amount]

;}

湊零錢問題:

計算機解決問題的唯一的解決辦法就是窮舉:如何窮舉:列出動態轉移方程

優化窮舉的方式:備忘錄和dp table

演算法Day06 演算法研習指導之滑動視窗

map key for int i 0 i s.size i for int j i 1 j s.size j if s i j 包含 t 的所有字母 更新結果 滑動視窗演算法偽碼框架 string s,t int left 0,right 0 res是符合要求的最小覆蓋子串 string res ...

演算法Day07 演算法研習指導之雙指標

左右指標 左右指標 如果鍊錶中不包含環,那麼這個指標最終會遇到空指標null.表示這個鍊錶已經到頭了,表示這個鍊錶不包含環 boolean hascycle listnode head return false boolean hacycle listnode head return false l...

day02 常用演算法 排序

氣泡排序 思路 相鄰的兩個數進行比較,會進行n 1輪比較,每一輪會比較n 1次之後,將陣列中最大的數排在最後 注意 每一次比較之後會交換變數值 package homework public class a02 for int i 0 i nums.length 1 i for int i 0 i ...