題目描述:
給定一個數組,它的第 i 個元素是一支給定股票第 i 天的價格。 若是你最多隻容許完成一筆交易(即買入和賣出一支股票一次),設計一個算法來計算你所能獲取的最大利潤。 注意:你不能在買入股票前賣出股票。java
思路:
動態規劃的 5 個步驟:算法
一、設定狀態
這道題實際上是一個典型的二維 dp 問題。「動態規劃」用於多階段最優化問題的求解。這裏天數表明每一個階段,即一天一天看,設置爲第一維。爲了消除後效性(前面的狀態肯定下來之後不會由於後面狀態而更改),將當天是否持股設置爲第二維的狀態。因而:數組
狀態 dp[i][j] 表示:在下標爲 i 的這一天,用戶手上持股狀態爲 j 所得到的最大利潤。優化
說明: j 只有 2 個值:0 表示不持股(特指賣出股票之後的不持股狀態),1 表示持股。 「用戶手上不持股」不表明用戶必定在下標爲 i 的這一天把股票拋售了;ui
二、思考狀態轉移方程
- dp[i][0] 怎樣轉移?
dp[i - 1][0] :固然能夠從昨天不持股轉移過來,表示從昨天到今天什麼都不操做,這一點是顯然的;設計
dp[i - 1][1] + prices[i]:昨天持股,就在下標爲 i 的這一天,我賣出了股票,狀態由 1 變成了 0,此時賣出股票,所以加上這一天的股價。code
綜上:dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] + prices[i]);leetcode
- dp[i][1] 怎樣轉移?
dp[i - 1][1] :昨天持股,今天什麼都不操做,固然能夠從昨天持股轉移過來,這一點是顯然的;it
-prices[i]:注意:狀態 1 不能由狀態 0 來,由於事實上,狀態 0 特指:「賣出股票之後不持有股票的狀態」,請注意這個狀態和「沒有進行過任何一次交易的不持有股票的狀態」的區別。io
所以,-prices[i] 就表示,在下標爲 i 的這一天,執行買入操做獲得的收益。注意:由於題目只容許一次交易,所以不能加上 dp[i - 1][0]。
綜上:dp[i][1] = max(dp[i - 1][1], -prices[i]);
三、考慮初始值
第 0 天不持股,顯然 dp[0][0] = 0;
第 0 天持股,顯然dp[0][1] = -prices[0]。
四、考慮輸出
從狀態轉移方程能夠看出,每一天的狀態都考慮了以前的狀態。在只發生一次交易的狀況下,持有這支股票必定不能使咱們得到最大利潤。所以輸出是 dp[len - 1][0],不多是持股的狀態 dp[len - 1][1],
做者:liweiwei1419 連接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/solution/bao-li-mei-ju-dong-tai-gui-hua-chai-fen-si-xiang-b/
代碼:
class Solution { public int maxProfit(int[] prices) { //定義狀態:dp[i][j]--在第i天,用戶持股狀態爲j時所得到的最大利潤。 //狀態關係:dp[i][0]=max(dp[i-1][0],dp[i-1][1]+price[i]); // dp[i][1]=max(dp[i-1][1],-price[i]); ---j不能由0->1,因此只是-price[i] //初始值:dp[0][0]=0--不持股利潤爲0;dp[0][1]=-price[0] //if(prices==null) return 0; wrong! int len=prices.length; if(len<2) return 0; int[][] dp=new int[prices.length+1][2]; dp[0][0]=0; dp[0][1]=-prices[0]; for(int i=1;i<prices.length;i++){ dp[i][0]=Math.max(dp[i-1][0],dp[i-1][1]+prices[i]); dp[i][1]=Math.max(dp[i-1][1],-prices[i]); } return dp[len-1][0]; } }