[LeetCode] Best Time to Buy and Sell Stock III 買股票的最佳時間之三
Say you have an array for which the ith element is the price of a given stock on day i.
Design an algorithm to find the maximum profit. You may complete at most two transactions.
Note:
You may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again).
這道是買股票的最佳時間系列問題中最難最複雜的一道,前面兩道
local[i][j] = max(global[i - 1][j - 1] + max(diff, 0), local[i - 1][j] + diff)
global[i][j] = max(local[i][j], global[i - 1][j])
其中區域性最優值是比較前一天並少交易一次的全域性最優加上大於0的差值,和前一天的區域性最優加上差值中取較大值,而全域性最優比較區域性最優和前一天的全域性最優。程式碼如下:
解法一:
class Solution { public: int maxProfit(vector<int> &prices) {if (prices.empty()) return 0; int n = prices.size(), g[n][3] = {0}, l[n][3] = {0}; for (int i = 1; i < prices.size(); ++i) { int diff = prices[i] - prices[i - 1]; for (int j = 1; j <= 2; ++j) { l[i][j] = max(g[i - 1][j - 1] + max(diff, 0), l[i - 1][j] + diff); g[i][j] = max(l[i][j], g[i - 1][j]); } } return g[n - 1][2]; } };
下面這種解法用一維陣列來代替二維陣列,可以極大的節省了空間,由於覆蓋的順序關係,我們需要j從2到1,這樣可以取到正確的g[j-1]值,而非已經被覆蓋過的值,參見程式碼如下:
解法二:
class Solution { public: int maxProfit(vector<int> &prices) { if (prices.empty()) return 0; int g[3] = {0}; int l[3] = {0}; for (int i = 0; i < prices.size() - 1; ++i) { int diff = prices[i + 1] - prices[i]; for (int j = 2; j >= 1; --j) { l[j] = max(g[j - 1] + max(diff, 0), l[j] + diff); g[j] = max(l[j], g[j]); } } return g[2]; } };
我們如果假設prices陣列為1, 3, 2, 9, 那麼我們來看每次更新時local 和 global 的值:
第一天兩次交易: 第一天一次交易:
local: 0 0 0 local: 0 0 0
global: 0 0 0 global: 0 0 0
第二天兩次交易: 第二天一次交易:
local: 0 0 2 local: 0 2 2
global: 0 0 2 global: 0 2 2
第三天兩次交易: 第三天一次交易:
local: 0 2 2 local: 0 1 2
global: 0 2 2 global: 0 2 2
第四天兩次交易: 第四天一次交易:
local: 0 1 9 local: 0 8 9
global: 0 2 9 global: 0 8 9
在網友@的提醒下,發現了其實上述的遞推公式關於local[i][j]的可以稍稍化簡一下,我們之前定義的local[i][j]為在到達第i天時最多可進行j次交易並且最後一次交易在最後一天賣出的最大利潤,然後網友@解釋了一下第 i 天賣第 j 支股票的話,一定是下面的一種:
1. 今天剛買的
那麼 Local(i, j) = Global(i-1, j-1)
相當於啥都沒幹
2. 昨天買的
那麼 Local(i, j) = Global(i-1, j-1) + diff
等於Global(i-1, j-1) 中的交易,加上今天干的那一票
3. 更早之前買的
那麼 Local(i, j) = Local(i-1, j) + diff
昨天別賣了,留到今天賣
但其實第一種情況是不需要考慮的,因為當天買當天賣不會增加利潤,完全是重複操作,這種情況可以歸納在global[i-1][j-1]中,所以我們就不需要max(0, diff)了,那麼由於兩項都加上了diff,所以我們可以把diff抽到max的外面,所以更新後的遞推公式為:
local[i][j] = max(global[i - 1][j - 1], local[i - 1][j]) + diff
global[i][j] = max(local[i][j], global[i - 1][j])
類似題目: