You are given an array prices where prices[i] is the price of a given stock on the ith day.
Find the maximum profit you can achieve. You may complete at most two transactions.
Note: You may not engage in multiple transactions simultaneously (i.e., you must sell the stock before you buy again).
Example 1:
**Input:** prices = [3,3,5,0,0,3,1,4]
**Output:** 6
**Explanation:** Buy on day 4 (price = 0) and sell on day 6 (price = 3), profit = 3-0 = 3.
Then buy on day 7 (price = 1) and sell on day 8 (price = 4), profit = 4-1 = 3.
Example 2:
**Input:** prices = [1,2,3,4,5]
**Output:** 4
**Explanation:** Buy on day 1 (price = 1) and sell on day 5 (price = 5), profit = 5-1 = 4.
Note that you cannot buy on day 1, buy on day 2 and sell them later, as you are engaging multiple transactions at the same time. You must sell before buying again.
Example 3:
**Input:** prices = [7,6,4,3,1]
**Output:** 0
**Explanation:** In this case, no transaction is done, i.e. max profit = 0.
Example 4:
**Input:** prices = [1]
**Output:** 0
Constraints:
1 <= prices.length <= 105
0 <= prices[i] <= 105
ac1 divide and conquer
time limit exceeded.
class Solution {
public int maxProfit(int[] prices) {
// edge cases
if (prices == null || prices.length <= 1) return 0;
// break into 2 parts
int profit = 0;
for (int i = 1; i < prices.length; i++) {
int tmp = max(prices, 0, i) + max(prices, i, prices.length - 1);
profit = Math.max(profit, tmp);
}
return profit;
}
private int max(int[] prices, int s, int e) {
// 1 transaction
int min = Integer.MAX_VALUE, max = 0;
for (int i = s; i <= e; i++) {
min = Math.min(min, prices[i]);
max = Math.max(max, prices[i] - min);
}
return max;
}
}
ac2: 2 pass
not intuitive
class Solution {
public int maxProfit(int[] prices) {
// edge cases
if (prices == null || prices.length <= 1) return 0;
int n = prices.length;
int[] dp = new int[n];
dp[0] = 0;
// first pass
int min = prices[0];
for (int i = 1; i < n; i++) {
min = Math.min(min, prices[i]);
dp[i] = Math.max(dp[i-1], prices[i] - min);
}
int max = prices[n-1], res = dp[n-1], secMax = 0;
// second pass
for (int i = n - 1; i >= 0; i--) {
max = Math.max(max, prices[i]);
secMax = Math.max(secMax, max - prices[i]);
dp[i] += secMax;
res = Math.max(res, dp[i]);
}
// result
return res;
}
}
/*
2 pass, l -> r and r -> l
*/
// This is intuitive
public int MaxProfitDpCompact1(int[] prices) {
if (prices.Length == 0) return 0;
var dp = new int[3, prices.Length];
for (int k = 1; k <= 2; k++) {
int min = prices[0];
for (int i = 1; i < prices.Length; i++) {
min = Math.Min(min, prices[i] - dp[k-1, i-1]);
dp[k, i] = Math.Max(dp[k, i-1], prices[i] - min);
}
}
return dp[2, prices.Length - 1];
}
// After some math optimization, we got this:
public int MaxProfitDpCompactFinal(int[] prices) {
int buy1 = int.MaxValue, buy2 = int.MaxValue;
int sell1 = 0, sell2 = 0;
for (int i = 0; i < prices.Length; i++) {
buy1 = Math.Min(buy1, prices[i]);
sell1 = Math.Max(sell1, prices[i] - buy1);
buy2 = Math.Min(buy2, prices[i] - sell1);
sell2 = Math.Max(sell2, prices[i] - buy2);
}
return sell2;
}