题目原文:
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.
题目大意:
给出一个数组,代表一个股票每一天的股价。现在你最多可以买卖两次,求出最大利益。
题目分析:
使用两个dp数组,dp1从正向扫描,其中dp1[i]表示0~i天买卖一次的最大收益,dp2从反向扫描,dp2[i]表示第i~n-1天买卖一次的最大收益。然后再并行扫一遍dp1和dp2,计算dp1[i]+dp2[i+1]的最大值。
dp1因为是正向扫的,所以维护当前子序列的最小值min,可以由dp[i-1]推出dp[i]:
dp[i]=max(dp[i-1],prices[i]-min)
,即如果在第i天卖了可以获得更大的收益,则在第i天卖掉,否则与在第i-1天之前卖是一样的。
同理,维护最大值max可以由dp2[i+1]推出dp2[i]:
dp2[i]=max(dp2[i+1],max-prices[i])
,道理同上。
最后有的同学还会提出这样的问题:如果只买卖一次是最优的呢?
没关系,dp1[n-1]就是一次买卖的最大收益。
源码:(language:java)
public class Solution {
public int maxProfit(int[] prices) {
if(prices.length<2)
return 0;
int[] dp1 = new int[prices.length];
int[] dp2 = new int[prices.length];
int min = prices[0];
for (int i = 1; i < prices.length; i++) {
if (prices[i] < min)
min = prices[i];
dp1[i] = Math.max(dp1[i - 1], prices[i] - min);
}
int max = prices[prices.length - 1];
for (int i = prices.length - 2; i >= 0; i--) {
if (prices[i] > max)
max = prices[i];
dp2[i] = Math.max(dp2[i + 1], max - prices[i]);
}
int profit = Math.max(dp1[prices.length-1], dp2[0]);
for (int i = 0; i < prices.length-1; i++) {
if (dp1[i] + dp2[i+1] > profit)
profit = dp1[i] + dp2[i+1];
}
return profit;
}
}
成绩:
3ms,beats 42.07%,众数2ms,38.19%
Cmershen的碎碎念:
一开始我想到的是套用股票第1题的函数求dp1和dp2,这样需要
n2
的复杂度,提交上去超时了。然后发现dp1可以用左边项来推,dp2也可以用右边项来推。这样就降到O(n)时间复杂度了。