原题网址:https://leetcode.com/problems/best-time-to-buy-and-sell-stock-iii/
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).
方法:双向扫描。
public class Solution {
private int[] forward(int[] prices) {
int[] max = new int[prices.length];
int low = prices[0];
for(int i=1; i<prices.length; i++) {
if (prices[i] < low) low = prices[i];
max[i] = Math.max(max[i-1], prices[i] - low);
}
return max;
}
private int[] backward(int[] prices) {
int[] max = new int[prices.length];
int high = prices[prices.length-1];
for(int i=prices.length-2; i>=0; i--) {
if (prices[i] > high) high = prices[i];
max[i] = Math.max(max[i+1], high - prices[i]);
}
return max;
}
public int maxProfit(int[] prices) {
if (prices == null || prices.length < 2) return 0;
int[] f = forward(prices);
int[] b = backward(prices);
int max = 0;
for(int i=0; i<prices.length; i++) if (f[i]+b[i]>max) max = f[i]+b[i];
return max;
}
}
方法二:动态规划。
public class Solution {
public int maxProfit(int[] prices) {
int firstBuy = Integer.MIN_VALUE;
int firstSell = 0;
int secondBuy = Integer.MIN_VALUE;
int secondSell = 0;
for(int price: prices) {
firstBuy = Math.max(firstBuy, - price);
firstSell = Math.max(firstSell, firstBuy + price);
secondBuy = Math.max(secondBuy, firstSell - price);
secondSell = Math.max(secondSell, secondBuy + price);
}
return secondSell;
}
}
上面把firstBuy、secondBuy理解为现金值,即买股票(投资)时现金为负数。如果把这两个变量理解为所需的现金数量,会更加容易理解一些:
public class Solution {
public int maxProfit(int[] prices) {
if (prices.length <= 1) return 0;
int firstBuy = Integer.MAX_VALUE;
int firstSell = 0;
int secondBuy = Integer.MAX_VALUE;
int secondSell = 0;
for(int price : prices) {
firstBuy = Math.min(firstBuy, price);
firstSell = Math.max(firstSell, price - firstBuy);
secondBuy = Math.min(secondBuy, price - firstSell);
secondSell = Math.max(secondSell, price - secondBuy);
}
return secondSell;
}
}
上面的程序等价于:
public class Solution {
public int maxProfit(int[] prices) {
if (prices.length <= 1) return 0;
int[] buy = new int[2];
int[] sell = new int[2];
Arrays.fill(buy, Integer.MAX_VALUE);
for(int price : prices) {
for(int j = 0; j < 2; j++) {
buy[j] = Math.min(buy[j], price - (j == 0 ? 0 : sell[j - 1]));
sell[j] = Math.max(sell[j], price - buy[j]);
}
}
return sell[1];
}
}
上面的程序等价于:
public class Solution {
public int maxProfit(int[] prices) {
if (prices.length <= 1) return 0;
int[][] buy = new int[prices.length][2];
int[][] sell = new int[prices.length][2];
for(int i = 0; i < prices.length; i++) {
for(int j = 0; j < 2; j++) {
if (i == 0 && j == 0) {
buy[i][j] = prices[i];
sell[i][j] = prices[i] - buy[i][j];
} else if (i == 0) {
buy[i][j] = prices[i] - sell[i][j - 1];
sell[i][j] = prices[i] - buy[i][j];
} else if (j == 0) {
buy[i][j] = Math.min(buy[i - 1][j], prices[i]);
sell[i][j] = Math.max(sell[i - 1][j], prices[i] - buy[i][j]);
} else {
buy[i][j] = Math.min(buy[i - 1][j], prices[i] - sell[i][j - 1]);
sell[i][j] = Math.max(sell[i - 1][j], prices[i] - buy[i][j]);
}
}
}
return sell[prices.length - 1][1];
}
}
交换i和j循环变量也是一样的:
public class Solution {
public int maxProfit(int[] prices) {
if (prices.length <= 1) return 0;
int[][] buy = new int[prices.length][2];
int[][] sell = new int[prices.length][2];
for(int j = 0; j < 2; j++) {
for(int i = 0; i < prices.length; i++) {
if (i == 0 && j == 0) {
buy[i][j] = prices[i];
sell[i][j] = prices[i] - buy[i][j];
} else if (i == 0) {
buy[i][j] = prices[i] - sell[i][j - 1];
sell[i][j] = prices[i] - buy[i][j];
} else if (j == 0) {
buy[i][j] = Math.min(buy[i - 1][j], prices[i]);
sell[i][j] = Math.max(sell[i - 1][j], prices[i] - buy[i][j]);
} else {
buy[i][j] = Math.min(buy[i - 1][j], prices[i] - sell[i][j - 1]);
sell[i][j] = Math.max(sell[i - 1][j], prices[i] - buy[i][j]);
}
}
}
return sell[prices.length - 1][1];
}
}
方法三:动态规划:
public class Solution {
public int maxProfit(int[] prices) {
if (prices.length <= 1) return 0;
int[][] local = new int[3][prices.length];
int[][] global = new int[3][prices.length];
for(int i = 1; i <= 2; i++) {
for(int j = 1; j < prices.length; j++) {
local[i][j] = Math.max(local[i][j - 1] + prices[j] - prices[j - 1],
global[i - 1][j - 1] + Math.max(0, prices[j] - prices[j - 1]));
global[i][j] = Math.max(global[i][j - 1], local[i][j]);
}
}
return global[2][prices.length - 1];
}
}