[LeetCode] #123 Best Time to Buy and Sell Stock III
LeetCode 题目,原题链接 https://leetcode.com/problems/best-time-to-buy-and-sell-stock-iii/。
问题描述:一定时间区间内一只股票,最多交易两次,两次交易无重叠区域,求最大收益。
参考:https://discuss.leetcode.com/topic/32288/2ms-java-dp-solution 。
Canonical Solution
这个问题是DP问题,因为存在两次交易,需要保存第一次交易的信息,给第二次交易做参考。
这个问题是在第 N 天或第 N 天之前完成第二次交易的卖出,获得的收益。
子问题是,在 N 天完成第二次交易的卖出,在第 N 天之前完成第二次交易的卖出,这两个获得的收益的最大值。再讲第二种情况进行分解,就可以分解成给 N 天时间,计算在第 2, 3, ,4, ,5, ..., N - 1 天 完成第二次交易的卖出获得的收益,这些收益中的最大值。(注:从第2天开始计算是因为有第一次交易存在,第一次交易在第0天买入,在第1天卖出,第二次交易最快只能在第2天卖出。)
使用一个一维数组 profit1 用于记录第一次交易的收益,profit[i] 表示在第 i 天完成第一次交易的卖出,获得的第一次交易的收益。
使用一个二维数组 porift 用于记录第二次交易的收益,profit[i][j] 表示在第 i 天完成第一次交易的卖出,第 j 天完成第二次交易的卖出(也可以不做第二次交易),获得的最大收益。
实际使用中二维数组可以省去,因为是线性单方向遍历,不需要回溯以前的记录。
class Solution {
public:
int maxProfit(vector<int>& prices) {
int N = prices.size();
vector<int> profit1(N, 0); // profit[i] 在第i天卖出第一支股票的收益
for (int i = 0; i < N; ++i) {
for (int j = i - 1; j >= 0; --j) {
if (prices[i] - prices[j] > profit1[i]) {
profit1[i] = prices[i] - prices[j];
}
}
}
// 依据 profit1 计算 profit,profit[i][j] 在第 i 天卖出第一支股票,第 j 天卖出第二支股票
int maxProfit = 0;
for (int i = 0; i < N; ++i) {
for (int j = i + 1; j < N; ++j) {
int profitij = 0;
for (int k = i; k < j; ++k) {
if (prices[j] - prices[k] > profitij) {
profitij = prices[j] - prices[k];
}
}
profitij += profit1[i];
if (profitij > maxProfit) {
maxProfit = profitij;
}
}
}
return maxProfit;
}
};
然而,这种方法Time Limit Exceeded
。
聪明人的方法
参考:https://discuss.leetcode.com/topic/32288/2ms-java-dp-solution
在评论区有一个人,Bef0rewind,对代码进行了解释。
public int maxProfit(int[] prices) {
// these four variables represent your profit after executing corresponding transaction
// in the beginning, your profit is 0.
// when you buy a stock ,the profit will be deducted of the price of stock.
int firstBuy = Integer.MIN_VALUE, firstSell = 0;
int secondBuy = Integer.MIN_VALUE, secondSell = 0;
// (-firstBuy) is min value beteen [0, curPrice.index], firstBuy itself is a negative value
// (firstSell) is max profit between [0, current.index], before update it is max profit between [0, current.index-1], after update is max(firstSell.before, curPrice + firstBuy(e.g. - minValue[0, curPrice.index]))
// (secondBuy) is max profit between [0,curPrice.index] under seen prices if you hold/buy a stock between[0, curPrice.index] and haven't sell it yet.
// (secondSell) is max profit between [0,curPrice.index] under seen prices if you buy a second stock between [0,curPrice.index];
for (int curPrice : prices) {
if (firstBuy < -curPrice) firstBuy = -curPrice; // the max profit after you buy first stock
if (firstSell < firstBuy + curPrice) firstSell = firstBuy + curPrice; // the max profit after you sell it
if (secondBuy < firstSell - curPrice) secondBuy = firstSell - curPrice; // the max profit after you buy the second stock
if (secondSell < secondBuy + curPrice) secondSell = secondBuy + curPrice; // the max profit after you sell the second stock
}
return secondSell; // secondSell will be the max profit after passing the prices
}
这是一个空手套白狼的故事,无本生意,先借钱,买股票,用卖出去的钱偿还买股票的借款。
遍历的时候考虑四种状态:firstBuy
第一次购买股票后口袋中的钱,firstSell
第一次售出股票后口袋中的钱, secondBuy
第二次购买股票后口袋中的钱,secondSell
第二次售出股票后口袋中的钱。