309. Best Time to Buy and Sell Stock with Cooldown

题目:

Say you have an array for which the i-th element is the price of a given stock on day i.

Design an algorithm to find the maximum profit. You may complete as many transactions as you like (ie, buy one and sell one share of the stock multiple times) with the following restrictions:

You may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again).
After you sell your stock, you cannot buy stock on next day. (ie, cooldown 1 day)

Example:

prices = [1, 2, 3, 0, 2]
maxProfit = 3
transactions = [buy, sell, cooldown, buy, sell]

题目大意:

给定一个数组,第i个元素代表某只股票在第i天的价格。

设计一个算法计算最大收益。你可以完成多次交易(亦即,多次买入、卖出同一只股票),需要满足下列限制:

你不可以在同一时间参与多个交易(亦即,在买入股票之前必须卖出)。
在卖出股票之后,你不可以在第二天马上买入。(亦即,需要一天的冷却(CD)时间)
测试用例见题目描述。

解题思路:

动态规划(Dynamic Programming)

时间复杂度:O(n)

本题与Best Time to Buy and Sell Stock II唯一的区别是在卖出股票后需要间隔至少一天才能再次买入。

对一天的状态有:buy买入,sell卖出,cooldown冷却。

但是对于这一天是否持股只有两种状态:持股状态(buy),没有持股状态(sell,cooldown)。

对于当天持股状态时,至当天的为止的最大利润有两种可能:1、今天没有买入,跟昨天持股状态一样;2、今天买入,昨天是冷却期,利润是前天卖出股票时候得到的利润减去今天股票的价钱。 二者取最大值。

对于当天未持股状态,至当天为止的最大利润有两种可能:1、今天没有卖出,跟昨天未持股状态一样;2、昨天持有股票,今天卖出了,利润是昨天持有股票时候的利润加上今天股票的价钱。 二者取最大值。

直至最后一天的状态应该是卖出状态。最终利润为sell[n-1];

状态转移方程:

sell[i] = max(sell[i-1], buy[i-1] + price[i]);

buy[i] = max(buy[i-1], sell[i-2] - price[i]);

/*
 另一种思路,首先用3个辅助数组表示buy,sell,rest
 buy[i]表示在第i天之前最后一个操作是买,此时的最大收益, 即第i天为买。

 sell[i]表示在第i天之前最后一个操作是卖,此时的最大收益。

 rest[i]表示在第i天之前最后一个操作是冷冻期,此时的最大收益。

 我们写出递推式为:

 buy[i]  = max(rest[i-1] - price, buy[i-1])
 sell[i] = max(buy[i-1] + price, sell[i-1])
 rest[i] = max(sell[i-1], buy[i-1], rest[i-1])

 上述递推式很好的表示了在买之前有冷冻期,买之前要卖掉之前的股票。
 一个小技巧是如何保证[buy, rest, buy]的情况不会出现,这是由于buy[i] <= rest[i], 即rest[i] = max(sell[i-1], rest[i-1]),
 即冷冻期前面只可能是冷冻期或者卖,绝对不会出现买!这保证了[buy, rest, buy]不会出现。

 另外,由于冷冻期的存在,我们可以得出rest[i] = sell[i-1],这样,我们可以将上面三个递推式精简到两个:

 buy[i]  = max(sell[i-2] - price, buy[i-1])
 sell[i] = max(buy[i-1] + price, sell[i-1])
*/
 public static int maxProfitON(int[] prices)
    {
        int size = prices.length;
        int[] buy = new int[size];
        int[] sell = new int[size];
        if (size < 2)
            return 0;

        buy[0] = -prices[0];
        buy[1] = Math.max(buy[0],-prices[1]);
        sell[0] = 0;
        sell[1] = Math.max(sell[0],buy[0]+prices[1]);

        //buy[i]  = max(rest[i-1]-price, buy[i-1])
        //sell[i] = max(buy[i-1]+price, sell[i-1])
        //根据最初始的状态转移方程,先写出来初始化

        for (int i = 2 ; i < prices.length ; i ++)
        {
            buy[i] = Math.max(buy[i-1],sell[i-2]-prices[i]);
            sell[i] = Math.max(sell[i-1],buy[i-1] + prices[i]);
        }

        return sell[size-1];

    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章