1. 程式人生 > 其它 >動態規劃演算法學習筆記

動態規劃演算法學習筆記

技術標籤:演算法和資料結構

常用演算法之動態規劃學習筆記

動態規劃問題的一般形式是求最值,求解動態規劃的核心問題是窮舉,窮舉所有的答案找最值。
因為這類問題存在 重疊子問題 的情況,所以需要 備忘錄(自頂向下)或者DP(Dynamic Programming) table(自底向上) 來優化窮舉過程。一定存在最優子結構(子問題的解答互相之間不影響),才能通過子問題的最值得到原問題最值。
因此有動態規劃三要素:重疊子問題、最優子結構、狀態轉移方程。
如斐波那契數列可以用動態規劃的思想進行優化,下面以經典樣例 湊零錢問題 為例,闡釋動態規劃問題的解決方式。
問題描述:
給你k種⾯值的硬幣,⾯值分別為c1, c2 … ck ,每種硬幣的數量⽆限,再給⼀個總⾦額amount ,問你最少需要⼏枚硬幣湊出這個⾦額,如果不可能湊出,演算法返回 -1 。

函式宣告如下:
int coinChange(int [] coins, int amount)
狀態轉移方程:
重點是列出狀態轉移方程,主要思路如下:

  1. 先確定狀態,原問題和子問題中變化的變數,硬幣數量無限,所以唯一的狀態是目標金額amount
  2. 確定dp 函式的定義:當前的目標金額為n,至少需要 dp(n) 個硬幣湊整
  3. 確定選擇並擇優,列出n取不同情況時的dp(n)取值,同時明確base case,也就是n = 0或n < 0特殊情況時的返回值
    得到狀態轉移方程:
    在這裡插入圖片描述

對應的Java程式碼:

public int coinChange(int[] coins, int amount) {
        int
[] dp = new int[amount + 1]; dp[0] = 0; for (int i = 1;i <= amount;i++) { boolean hasChange = false; int min = amount; for (int coin : coins) { int index = i - coin; if (index >= 0 && dp[index] >= 0) { int
value = dp[index] + 1; if (min > value) { min = value; } hasChange = true; } } if (!hasChange) { dp[i] = -1; } else { dp[i] = min; } } return dp[amount]; }