一个简单的例子由易到难理解动态规划
在本文中,我們先用最簡單的方法來解決問題,然后一步步進(jìn)階,在這個不斷優(yōu)化算法的過程中理解動態(tài)規(guī)劃。
力扣 322. 零錢兌換 問題
1. 暴力遞歸
假設(shè) coins[] = [2, 4, 5],amount = 10,想要求 amount = 10 可以求
min ( 1 + coinChange(coins, amount - 2), 1 + coinChange(coins, amount - 4), 1 + coinChange(coins, amount - 5) )
即假設(shè)已經(jīng)知道了 amount = 8、amount = 6、amount = 5 時 所需的最少的硬幣個數(shù), 那只要再加 1 個硬幣就可以湊夠 10,在這三者中選最少的一個就是答案。
繼續(xù)想的話,求 amount = 8,也是同樣的方法,就是不斷往下遞歸。
public int coinChange(int[] coins, int amount) {//確定遞歸結(jié)束的條件if(amount == 0) return 0;if(amount < 0) return -1;int res = Integer.MAX_VALUE;//遍歷求各 coinChange(amount-coin) 的值,求出最小值for(int coin: coins){int subProblem = coinChange(coins, amount-coin);if(subProblem == -1) continue;res = Math.min(res, subProblem + 1);}return res==Integer.MAX_VALUE ? -1 : res; }為了更好理解,來畫一下遞歸樹
從上圖就可以看出來,這種方法就是在用遞歸把所有的可能窮舉出來,然后取最小值。
但這個方法存在重疊子問題,即存在大量的重復(fù)計(jì)算。有很多問題我們已經(jīng)計(jì)算過,但當(dāng)遞歸到那里時,還是要再算一次。
所以為解決這個問題,下面采用帶備忘錄的遞歸解法。
2. 帶備忘錄的遞歸解法
帶備忘錄就是把已經(jīng)計(jì)算過的值存起來,以此來減少不必要的計(jì)算。
每次計(jì)算完后,將值存入一個數(shù)組中,每次計(jì)算前判斷一下備忘錄中有沒有存,有則可以直接獲取,不需要再進(jìn)行漫長的遞歸運(yùn)算了。
int[] count; public int coinChange(int[] coins, int amount) {//建立數(shù)組,進(jìn)行初始化count = new int[amount+1];Arrays.fill(count, -2);return(coin(coins, amount)); } public int coin(int[] coins, int amount){if(amount == 0) return 0;if(amount < 0) return -1;//判斷是否存入備忘錄if(count[amount] != -2)return count[amount];int res = Integer.MAX_VALUE;for(int coin:coins){int subProblem = coin(coins, amount-coin);if(subProblem == -1) continue;res = Math.min(res, subProblem+1);}//存入count[amount] = (res == Integer.MAX_VALUE) ? -1 : res;return count[amount]; }現(xiàn)在似乎已經(jīng)很完善了,但備忘錄解法是 自頂向下 的,是從一個規(guī)模較大的原問題,一層一層向下分解成子問題,直至底層,然后再逐層返回結(jié)果。
動態(tài)規(guī)劃是 自底向上 的解出最優(yōu)值。下面來改造一下這個方法。
3. dp 數(shù)組的迭代解法
采用 自底向上 就是要從底層狀態(tài)一直算到所求狀態(tài)
定義一個 dp 數(shù)組,dp[i] 表示為 amount = i 時所需的最少的硬幣個數(shù)
這就是最后的動態(tài)規(guī)劃的解法了。
動態(tài)規(guī)劃最核心的是寫出狀態(tài)轉(zhuǎn)移方程,這也是最困難的一步,多多練習(xí),熟能生巧。
本文源于學(xué)習(xí) labuladong的算法小抄 ,大佬寫的明白易懂,沒有什么晦澀的地方。
總結(jié)
以上是生活随笔為你收集整理的一个简单的例子由易到难理解动态规划的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ACdream 1069 无耻的出题人
- 下一篇: matlab subs命令,Matlab