Description:
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).
———————————————————————————————————————————————————
Solution:
題意:任意兩天買入賣出,求獲得利潤的最大值。(賣出必須在買入之後,第二次買入必須在第一次買入之後)
思路:一開始想法是沿用122. Best Time to Buy and Sell Stock II的峯谷算法,取兩個峯谷間差值最大的相加輸出,結果WA了。出錯的測試用例是:[1,2,4,2,5,7,2,4,9,0],如圖:
可以看到,在這組測試用例中一共有三個坡(增序子序列):[1,2,4],[2,5,7],[2,4,9],按照峯谷算法思路應該輸出(7-2)+(9-2)=12,但實際上正確結果應該是(7-1)+(9-2)=13。
分析兩者區別,發現錯誤原因是1<2,應該選擇1作爲第一個交易的買入點,而不應該選擇2,也就是說峯谷算法失效了,取而代之的是我們應該找到兩個極大值和極小值差值最大的子序列作爲輸出,然而實際上這很難實現,因爲我們只能找到最近的極大值(4)和差值最大的極大值(9),很難判斷到底既不是最近也不是差值最大的極大值(7)是不是我們應該找的值。所以此時我們應該改變思路:
class Solution {
public:
int maxProfit(vector<int>& prices) {
// 4種狀態:
// 1.有一個買入:states[][0]表示第一次買入價格
// 2.有一個買入和一個賣出:states[][1]表示第一次賣出得到的利潤
// 3.有兩個買入和一個賣出:states[][2]表示在第一次交易的利潤上,第二次買入的價格
// 4.有兩個買入和兩個賣出:states[][3]表示在第一次交易的利潤上,第二次賣出的利益
int states[2][4] = {INT_MAX, 0, INT_MIN, 0};
int next = 1, cur = 0;
for (int i = 0; i < prices.size(); i++) {
// 第一個買入的最低點
states[next][0] = min(states[cur][0], prices[i]);
// 第一個賣出的最高點
states[next][1] = max(states[cur][1], prices[i] - states[cur][0]);
// 在第一個交易利益的基礎上,第二個買入的最低點
states[next][2] = max(states[cur][2], states[cur][1] - prices[i]);
// 在第一個交易利益的基礎上,第二個賣出的最高點
states[next][3] = max(states[cur][3], states[cur][2] + prices[i]);
// 保存當前狀態,切換到下一個狀態
swap(next, cur);
}
// 要麼只有一個交易(states[cur][1]),要麼是累計的交易(states[cur][3])
return max(states[cur][1], states[cur][3]);
}
};