LeetCode -- Best Time to Buy and Sell Stock with Cooldown

Question:

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 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]

Analysis:

给定一个数组,其中第i个元素的值表示第i天股票的价格。设计一个算法找到最大利润,你可以按照你的意愿进行多次交易,但是有如下限制:

1. 不能同时进行多次交易(即在你下次买入股票之前应该先卖出);

2. 当你卖掉所有股票后,不能马上在第二天买入(即cooldown为1天)。

思路:(简直被这种动态规划的题目虐死了啊!) 

 看的网络上的思路:

对于每天来说,所可能处于的状态只有三种:要么是买入的状态,要么是卖出的状态,要么是cooldown的状态。而如果按照当前是否持股来分类,则可以分为两类,持股的状态(买入)和未持股的状态(卖出或cooldown)。下面分别讨论这两种情况:

a. 持股的状态:可能今天没有进行操作,跟昨天持股的状态一致;可能前天卖出了股票,今天买入了股票。为了使最后的利益最大我们应该取两者的最小值,为了操作的一致性,加入符号变为求两者的最大值,写成公式的形式为:buy[i] = max(buy[i-1], sell[i-2] - price[i]);

b. 未持股的状态:可能今天没有操作,与昨天未持股的状态一致;可能昨天买入了股票而今天卖出了股票。为了使盈利最大我们应该取两者的最大值,写成公式的行为为: sell[i] = max(sell[i-1], buy[i-1] + price[i]).

最后返回sell数组的最后一个元素就是交易的最大盈利。

Answer:

public class Solution {
    public int maxProfit(int[] nums) {
        if(nums == null || nums.length == 0)
            return 0;
        int[] buy = new int[nums.length];
        int[] sell = new int[nums.length];
        buy[0] = -nums[0];
        sell[0] = 0;
        for(int i=1; i<nums.length; i++) {
            sell[i] = Math.max(sell[i-1], buy[i-1] + nums[i]);
            if(i >= 2)
                buy[i] = Math.max(buy[i-1], sell[i-2] - nums[i]);
            else
                buy[i] = Math.max(buy[i-1], -nums[i]);
        }
        return sell[nums.length - 1];
    }
}

上面解决方案的时间复杂度为O(n),空间复杂度为O(n)。

分析上面的解决方案发现在计算的过程中,我们额外使用了n的buy数组和sell数组,但是每次循环时我们使用的仅仅是上一次循环的buy,sell,比较特殊的是使用了sell[i-2],因此我们可以再使用一个额外的变量在每次循环时保存上上次的sell信息即可。

改进后的版本为:

public class Solution {
    public int maxProfit(int[] nums) {
        if(nums == null || nums.length == 0)
            return 0;
        int buy = -nums[0];
        int sellpre = 0;
        int sell = 0;
        for(int i=1; i<nums.length; i++) {
            int temp = sell;
            sell = Math.max(sell, buy + nums[i]);
            if(i >= 2) 
                buy = Math.max(buy, sellpre - nums[i]);
            else
                buy = Math.max(buy, -nums[i]);
            sellpre = temp;
        }
        return sell;
    }
}
原文地址:https://www.cnblogs.com/little-YTMM/p/5206878.html