給定一個數組,它的第 i 個元素是一支給定股票第 i 天的價格。
如果你最多只允許完成一筆交易(即買入和賣出一支股票),設計一個算法來計算你所能獲取的最大利潤。
注意你不能在買入股票前賣出股票。
示例 1:
輸入: [7,1,5,3,6,4] 輸出: 5 解釋: 在第 2 天(股票價格 = 1)的時候買入,在第 5 天(股票價格 = 6)的時候賣出,最大利潤 = 6-1 = 5 。 注意利潤不能是 7-1 = 6, 因為賣出價格需要大於買入價格。
示例2:
輸入: [7,6,4,3,1] 輸出: 0 解釋: 在這種情況下, 沒有交易完成, 所以最大利潤為 0。
解法一: 暴力解決法
算法思想:
我們需要找出給定數組中兩個數字之間的最大差值(即,最大利潤)。此外,第二個數字(賣出價格)必須大於第一個數字(買入價格)。
對於每組 i 和 j (j > i)我們需要找出max(prices[j] - prices[i])
代碼如下:
func maxProfit(_ prices: [Int]) -> Int { guard prices.count > 0 else {return 0} var maxProfit: Int = 0 for i in 0..<prices.count - 1 { for j in i+1..<prices.count { maxProfit = max(maxProfit, prices[j] - prices[i]) } } return maxProfit }
解法二:動態規划
算法思想:
動態規划的3個步驟:
- 設定狀態
- 推導方程
- 起始值和輸出
這里狀態的設置得稍微想一想,數組的問題一般我們得固定其中一個變量。這道題有兩個變量,一個是“買入”,另一個是“賣出”,這里我們固定“賣出”變量,“買入”變量一定在它之前。
因此狀態dp[i]表示:在索引為 i 的這一天,用戶所能獲得的最大利潤。
下面思考狀態轉移,我們就要想dp [i] 的從前面的狀態值轉移過來,但是我們就會發現新的問題dp[i - 1]、dp[i - 2]、……、dp[0],狀態轉移無從下手。這里就說明:狀態還不夠,得把“買入”和“賣出”操作加入到狀態的設置中。
於是下面修改狀態的定義:
- dp[i][0]表示:在索引為 i 的這一天,用戶手上不持股所能獲得的最大利潤;
1、 0 一般表示沒有,在索引為 i 的這一天,手上沒有股票,語義上也是清晰的,下面對狀態 1 的理解也是一樣; 2、 “用戶手上不持股”不代表用戶一定在索引為 i 的這一天把股票拋售了; 3、 在索引為 i 的這一天具體應該這樣理解:從索引為 0 的天數開始,到索引為 i 的這一天,因此,這個狀態的設置具有“前綴”的意味,因此輸出是 dp[len - 1][0],不可能是 dp[len - 1][1],在只發生一次交易的情況下,持有這支股票一定不能使我們獲得最大利潤。
- 狀態dp[i][1]表示:在索引為 i 的這一天,用戶手上持股所能獲得最大的利潤。
下面考慮狀態轉移方程:
dp[i][0]
可以由誰轉移過來?
dp[i - 1][0]
:今天不持股,假設我今天什么都不操作,當然可以從昨天不持股轉移過來,這一點是顯然的-
dp[i - 1][1] + prices[i]:昨天持股,就在索引為 i 的這一天,我賣出了股票,狀態由 1 變成了 0,此時獲得利潤,因此加上這一天的股價。
綜上:
dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] + prices[i]);
2. dp[i][1]
可以由誰轉移過來?
-
dp[i - 1][1]
:今天持股,假設我今天什么都不操作,當然可以從昨天持股轉移過來,這一點是顯然的; -
-prices[i]:**請注意:**狀態 1 不能由狀態 0 來,因為事實上,狀態 0 特指:“賣出股票以后不持有股票的狀態”,請注意這個狀態和“沒有進行過任何一次交易的不持有股票的狀態”的區別。
因此,
-prices[i]
就表示,在索引為i
的這一天,執行買入操作得到的收益,再次強調:因為題目只允許一次交易,因此不能加上dp[i - 1][0]
。
綜上:dp[i][1] = max(dp[i - 1][1], -prices[i]);
在新修改的定義中,我們已經分析出了輸出dp[len - 1][0]
public int maxProfit(int[] prices) { int len = prices.length; if (len < 2) { return 0; } // 0:用戶手上不持股所能獲得的最大利潤,特指賣出股票以后的不持股,非指沒有進行過任何交易的不持股 // 1:用戶手上持股所能獲得的最大利潤 // 注意:因為題目限制只能交易一次,因此狀態只可能從 1 到 0,不可能從 0 到 1 // 狀態轉移方程: // dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] + prices[i]) // dp[i][1] = max(dp[i - 1][1], -prices[i]) int[][] dp = new int[len][2]; dp[0][0] = 0; dp[0][1] = -prices[0]; for (int i = 1; i < len; 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]; }
以上就是股票最大收益算法,希望對大家有所幫助!!!