123. Best Time to Buy and Sell Stock III (Array; DP)
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).
法I:把要求的东西profits设成状态。
第一次:从左往右扫描,同I一样记录下minimum value,不同的是,不仅要知道最大profit,还要记录下每个当前位置的profit(需要一个数组),为了之后与第二次扫描的结果相加。
第二次:从右往左scan,记录下maximum value, 计算profit,再加上之前第一次扫描从0到当前位置的profit,得到总的profit。
时间复杂度O(n) *2
class Solution { public: int maxProfit(vector<int> &prices) { if(prices.empty()) return 0; int size = prices.size(); int maxProfit = 0; int* profits = new int [size]; //表示从0到i的最大利润 int* profits_from_last = new int [size]; //表示从i到size-1的最大利润 //initial status profits[0] = 0; int minValue = prices[0]; //scan from start for(int i = 1; i< size; i++) { if(prices[i] < minValue) //save the minimum value { minValue = prices[i]; profits[i] = profits[i-1]; } else //caculate the profit from minimum value to currentand compare to previous maximum profit(profits[i-1]) { profits[i] = max(prices[i]-minValue,profits[i-1]); } } //initial status profits_from_last[size-1] = 0; int maxValue = prices[size-1]; //scan from last for(int i = size-2; i >=0 ; i--) { if(prices[i] > maxValue) //save the maximum value { maxValue = prices[i]; profits_from_last[i] = profits_from_last[i+1]; } else //caculate the profit from current to maximum value and compare to previous maximum profit(profits_from_last[i+1]) { profits_from_last[i] = max(maxValue-prices[i],profits_from_last[i+1]); } int profit = profits[i] + profits_from_last[i]; //calculate profits of two transactions if(profit>maxProfit) { maxProfit = profit; } } return maxProfit; } };
Note:第二次scan不必存储每个状态,所以只需一个变量存储到目前为止第二次扫描的最大利润。
class Solution { public: int maxProfit(vector<int> &prices) { if(prices.empty()) return 0; int size = prices.size(); int maxProfit = 0; int* profits = new int [size]; //表示从0到i的最大利润 int* profits_from_last = new int [size]; //表示从i到size-1的最大利润 //initial status profits[0] = 0; int minValue = prices[0]; //scan from start for(int i = 1; i< size; i++) { if(prices[i] < minValue) //save the minimum value { minValue = prices[i]; profits[i] = profits[i-1]; } else //caculate the profit from minimum value to currentand compare to previous maximum profit(profits[i-1]) { profits[i] = max(prices[i]-minValue,profits[i-1]); } } //initial status int maxSecondProfits = 0; int maxValue = prices[size-1]; //scan from last for(int i = size-2; i >=0 ; i--) { if(prices[i] > maxValue) //save the maximum value { maxValue = prices[i]; } else //caculate the profit from current to maximum value and compare to previous maximum profit(maxSecondProfits) { maxSecondProfits = max(maxValue-prices[i],maxSecondProfits); } int profit = profits[i] + maxSecondProfits; //calculate profits of two transactions if(profit>maxProfit) { maxProfit = profit; } } return maxProfit; } };
法II:进一步提升space efficiency。扫描一次,从而不用存储第一次交易的状态。
在扫描的时候,把当前点看作两次交易都完成的点,计算当前最大利润。
然后再依次更新把当前点看作第二次买入点的最大利润,看作第一次卖出点的最大利润,第一次买入点的最大利润,这些都为了在下一个循环用来更新状态。
所以,需要用4个变量存储到当前日为止第1/2次买入/卖出的利润最大值。
时间复杂度O(n)
class Solution { public: int maxProfit(vector<int>& prices) { int dates = prices.size(); if(dates <= 1) return 0; int hold1 = INT_MIN, hold2 = INT_MIN;//buy stock int release1 = 0, release2 = 0;//sell stock for(int i = 0; i < dates; i++){ release2 = max(release2, hold2+prices[i]);// The maximum if we've just sold 2nd stock so far. hold2 = max(hold2, release1 - prices[i]); // The maximum if we've just buy 2nd stock so far. release1 = max(release1, hold1+prices[i]);// The maximum if we've just sold 1nd stock so far. hold1 = max(hold1, -prices[i]); // The maximum if we've just buy 1st stock so far. } return release2; } };