LeetCode 121. Best Time to Buy and Sell Stock (详细分析maxSubArray)

 

 

 

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;
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值