股票的最大收益(最多交易两次)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).

解决:

【题意】用一个数组表示股票每天的价格,数组的第i个数表示股票在第i天的价格。最多交易两次,手上最多只能持有一支股票,求最大收益。

例子:

Prices: 1 4 5 7 6 3 2 9
left = [0, 3, 4, 6, 6, 6, 6, 8]
right= [8, 7, 7, 7, 7, 7, 7, 0]

The maximum profit = 13

最简单的方法就是对每一个时间点,将其所有两边的数组都执行一次Best Time to Buy and Sell Stock I的解法,但这会带来O(N^2)的时间复杂度。会超时。

① 双向动态规划。当计算prices[0]到prices[i]的最大收益时,我们已经计算过prices[0]到prices[i-1]的最大收益了,prices[0]到prices[i]的最大收益应该是当前卖出能获得的最大收益和prices[0]到prices[i-1]的最大收益中,二者较大的那个。我们可以利用这个之前计算的结果降低时间复杂度(不过代价是额外空间),所以需要把prices[0]到prices[i]的最大收益存在left[i]数组中。具体解法和I是一样的,也是维护一个前半段最小值。

分别得出以i点为分割点,左半段最大收益的数组left,和右半段最大收益的数组right后,我们就可以遍历一遍这两个数组,找出最大的left+right组合。实际上,该解法就是将I的解法双向各执行一遍并记录结果。

class Solution { //3ms
    public int maxProfit(int[] prices) {
        if (prices == null || prices.length == 0) return 0;
        int len = prices.length;
        int[] left = new int[len];
        int[] right = new int[len];
        int leftmin = prices[0];
        int rightmax = prices[len - 1];
        for (int i = 1;i < prices.length;i ++){//左半段最大收益
            leftmin = Math.min(leftmin,prices[i]);
            left[i] = Math.max(prices[i] - leftmin,left[i - 1]);
        }
        for (int i = prices.length - 2;i >= 0;i --){//右半段最大收益
            rightmax = Math.max(rightmax,prices[i]);
            right[i] = Math.max(rightmax - prices[i],right[i + 1]);
        }
        int max = 0;
        for (int i = 0;i < prices.length;i ++){
            if (left[i] + right[i] > max){
                max = left[i] + right[i];
            }
        }
        return max;
    }
}

② discuss中看到的进化版,只使用一个数组即可。

class Solution { //2ms
    public int maxProfit(int[] prices) {
        if (prices.length < 2) return 0;
        int[] profit = new int[prices.length];
        for (int k = 0;k < 2;k ++){
            int maxBuy = profit[0] - prices[0];//左侧最大利益
            for (int i = 1;i < prices.length;i ++){
                int tmp = profit[i];
                profit[i] = Math.max(profit[i - 1],prices[i] + maxBuy);
                maxBuy = Math.max(maxBuy,tmp - prices[i]);
            }
        }
        return profit[prices.length - 1];
    }
}

转载于:https://my.oschina.net/liyurong/blog/1591037

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值