股票交易
121 Best Time to Buy and Sell Stock
三种解决方法
public static int maxProfit(int[] arr) {
if (arr == null || arr.length < 2) return 0;
int[] dp = new int[arr.length-1];
dp[0] = arr[1]-arr[0];
for (int i = 1; i < arr.length-1; i++) {
dp[i] = Math.max(dp[i-1], arr[i+1]-arr[0]);
}
for (int row = 1; row < arr.length-1; row++) {
dp[row-1] = Integer.MIN_VALUE;
for (int column = row; column < arr.length-1; column++) {
int max = Math.max(arr[column+1]-arr[row], dp[column-1]);
dp[column] = Math.max(max, dp[column]);
}
}
return dp[arr.length-2];
}
public static int maxProfit2(int[] arr) {
if (arr == null || arr.length < 2) return -1;
// 价格数组可以看成是升升降降的子数组组成,
// 从最初的升序子数组开始,往后遇到升的就将高度相加,降的就减去相应高度,
// 这样就能统计出这一段的最低与最高的差值,
// 直到小于0代表这一段的结束,从下一个升序子数组开始继续统计
int sum = 0, max = 0;
for (int i = 1; i < arr.length; i++) {
sum = Math.max(0, sum + arr[i] - arr[i - 1]);
max = Math.max(sum, max);
}
return max;
}
public static int maxProfit3(int[] arr) {
if (arr == null || arr.length < 2) return -1;
// min 表示i之前最低的价格,arr[i]-min 代表i天卖出能获得的最大利润
int max = 0, min = arr[0];
for (int i = 1; i < arr.length; i++) {
max = Math.max(max, arr[i]-min);
min = Math.min(min, arr[i]);
}
return max;
}
309,Best Time to Buy and Sell Stock with Cooldown
包含冷却期
public int maxProfit(int[] prices) {
if(prices.length<2) return 0;
int[] buy = new int[prices.length];
int[] sell = new int[prices.length];
buy[0]=-prices[0];
buy[1]=Math.max(buy[0], -prices[1]);
sell[0]=0;
sell[1]=Math.max(0, buy[0]+prices[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[prices.length-1];
}
变量代替数组
public int maxProfit(int[] prices) {
int sell = 0, pre_sell = 0, buy = Integer.MIN_VALUE, pre_buy;
for (int price : prices) {
pre_buy = buy;
buy = Math.max(buy, pre_sell-price);
pre_sell = sell;
sell = Math.max(sell, pre_buy+price);
}
return sell;
}
714, Best Time to Buy and Sell Stock with Transaction Fee
需要交易费用的股票交易
public int maxProfit(int[] prices, int fee) {
// 方法一
// if(prices == null || prices.length < 2) return 0;
// int[] buy = new int[prices.length];
// int[] sell = new int[prices.length];
// buy[0] = -prices[0];
// buy[1] = Math.max(buy[0], -prices[1]);
// sell[1] = Math.max(sell[0], buy[0]+prices[1]-fee);
// for(int i = 2; i < prices.length; i++) {
// buy[i] = Math.max(buy[i-1], sell[i-1]-prices[i]);
// sell[i] = Math.max(sell[i-1], buy[i-1]+prices[i]-fee);
// }
// return sell[prices.length-1];
int buy = -prices[0], sell = 0;
for(int i = 1; i < prices.length; i++) {
int pre_buy = buy;
buy = Math.max(buy, sell-prices[i]);
sell = Math.max(sell, pre_buy+prices[i]-fee);
}
return sell;
}
123, Best Time to Buy and Sell Stock III
public int maxProfit(int[] prices) {
// if(prices == null || prices.length == 0) return 0;
// int[] sell = new int[2];
// int[] buy = new int[2];
// buy[0] = buy[1] = -prices[0];
// for (int i = 1; i < prices.length; i++) {
// int buy0 = buy[0];
// buy[0] = Math.max(buy[0], -prices[i]);
// int sell0 = sell[0];
// sell[0] = Math.max(sell[0], buy0+prices[i]);
// int buy1 = buy[1];
// buy[1] = Math.max(buy[1], sell0-prices[i]);
// sell[1] = Math.max(sell[1], buy1+prices[i]);
// }
// return sell[1];
// 对上面代码进行优化
// sell1 代表第一次交易在该位置卖出的最大值;sell2 同理代表第二次
// buy1 代表第一次交易在该位置买进的最大值;buy2 同理代表第二次
if(prices == null || prices.length == 0) return 0;
int sell1 = 0, sell2 = 0, buy1 = Integer.MIN_VALUE, buy2 = Integer.MIN_VALUE;
for(int price : prices) {
sell2 = Math.max(sell2, buy2+price);
buy2 = Math.max(buy2, sell1-price);
sell1 = Math.max(sell1, buy1+price);
buy1 = Math.max(buy1, -price);
}
return sell2;
}
有个问题:题目说至多两次交易,也就是说存在一次交易大于两次交易的情况,那么代码中返回 sell2 能够包含一次交易的情况吗?可以,因为在一开始我们将 buy1 ,buy2 ,sell1, sell2 都设置相同的值,在一次交易大于两次交易的情况下 sell1 与 sell2 始终相等,为什么这么说?
我们可以将数组看作是升升降降的曲线,可以判定只有三种情况下才会出现一次交易大于两次交易的情况,分别是:单升,降升降,升降。总结下三者共有特征就是只包含一次升过程,该情况下sell1 与 sell2 始终相等。
188, Best Time to Buy and Sell Stock IV
public int maxProfit(int k, int[] prices) {
if (prices == null || k == 0) return 0;
// 为了防止k过大导致的Memory Limit Exceeded
// 数组可以看成是升升降降的曲线
// 当k大于等于数组一半时,所谓最大利润就是所有升序曲线高度和
if (k >= prices.length/2) return quick(prices);
int[] buy = new int[k];
int[] sell = new int[k];
Arrays.fill(buy, Integer.MIN_VALUE);
for(int price : prices) {
sell[0] = Math.max(sell[0], buy[0]+price);
buy[0] = Math.max(buy[0], -price);
for(int i = 1; i < k; i++) {
sell[i] = Math.max(sell[i], buy[i]+price);
buy[i] = Math.max(buy[i], sell[i-1]-price);
}
}
return sell[k-1];
}
private int quick(int[] prices) {
int profit = 0, len = prices.length;
for(int i = 1; i < len; i++) {
if (prices[i] > prices[i-1]) profit += prices[i]-prices[i-1];
}
return profit;
}