Say you have an array for which the ith element is the price of a given stock on day i.
If you were only permitted to complete at most one transaction (i.e., buy one and sell one share of the stock), design an algorithm to find the maximum profit.
Note that you cannot sell a stock before you buy one.
Example 1:
Input: [7,1,5,3,6,4]
Output: 5
Explanation: Buy on day 2 (price = 1) and sell on day 5 (price = 6), profit = 6-1 = 5.
Not 7-1 = 6, as selling price needs to be larger than buying price.
Example 2:
Input: [7,6,4,3,1]
Output: 0
Explanation: In this case, no transaction is done, i.e. max profit = 0.
一开始没有仔细看题,没注意到只能买卖一次。。结果自己想了巨复杂的动态规划然后还超时了。
思考:
最优结果是 第i天买入,第j天卖出(i<j)。那么第i天之前不能有比第i天股价还便宜的时候,否则在那天买,第j天卖不就赚的更多了么。同理,第j天后也不能有比第j天还要高的股价。
我们只需要遍历除了第一天之外的所有天,找出在每一天卖出股票的最大可能收益,然后再求最大值即可。
每一天卖出股票的最大可能受益: 当天股价减去历史最低股价(相对于当天的历史)
空间优化后的代码如下:
class Solution {
public int maxProfit(int[] prices) {
if(prices==null || prices.length==0){
return 0;
}
int n = prices.length;
int max_profit = 0;//
int lowest_price = prices[0];
for(int i = 1;i<n;i++){
lowest_price = Math.min(lowest_price,prices[i]);//到第i天为止的最低股价
if(prices[i] - lowest_price > max_profit)//在第i天卖出股票的最大可能受益
max_profit = prices[i]-lowest_price;
}
return max_profit;
}
}
----------------------------------------------------------------------------------
方法二:将问题转为收益的连续最大子列和
如Input: [7,1,5,3,6,4]变为
gain:[-6,4,-2,3,-2] (由当天股价减去前一天的股价而来)
现在只需要去求gain数组的最大连续子列和即可。
那么为什么gain数组的最大连续子列和就是原问题的最大收益呢?
这里可以这样理解,gain的每一项都是买入再在下一天卖出,那么gain数组的连续部分gain[i]到gain[j]相加代表的是:
在第i天买入,第i+1天卖出
在第i+1天买入,第i+2天卖出
........
在第j-2天买入,第j-1天卖出
在第j-1天买入,第j天卖出
这一系列操作恰好等于一个操作: 第i天买入,第j天卖出!(观察上面的一系列操作,中间天的操作都是既卖又买的,互相抵消了)
因此gain[i]到gain[j]的连续子列和 就是 第i天买入,并在第j天卖出的收益
所以我们只需要求出gain数组的最大连续子列和,就等于 max( prices[j]-prices[i] )
如果当前股价数组无法盈利,那么我们可以不买也不卖,即收益为0。所以初始值设为0.
class Solution {
public int maxProfit(int[] prices) {
if(prices==null || prices.length<=1){
return 0;
}
int n = prices.length;
int maxEndingHere = 0;
int maxSoFar = 0;
for(int i = 1;i<n;i++){
maxEndingHere = Math.max(maxEndingHere,0) + prices[i]-prices[i-1];
maxSoFar = Math.max(maxEndingHere,maxSoFar);
}
return maxSoFar;
}
}