[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第二次售出股票后口袋中的钱。

posted @ 2017-09-18 12:12  JingeTU  阅读(228)  评论(0编辑  收藏  举报