LeetCode 123. Best Time to Buy and Sell Stock II,小米2016校招 风口的猪-中国牛市

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).

小米的题

题目描述

风口之下,猪都能飞。当今中国股市牛市,真可谓“错过等七年”。 给你一个回顾历史的机会,已知一支股票连续n天的价格走势,以长度为n的整数数组表示,数组中第i个元素(prices[i])代表该股票第i天的股价。 假设你一开始没有股票,但有至多两次买入1股而后卖出1股的机会,并且买入前一定要先保证手上没有股票。若两次交易机会都放弃,收益为0。 设计算法,计算你能获得的最大收益。 输入数值范围:2<=n<=100,0<=prices[i]<=100 
输入例子:
这两道题是一样。 网上有答案,我也参考了。这里我说一下思路过程。

1,首先我们假设我们可以用O(N)的复杂度解决之买卖一次的情况,即LeetCode121点击打开链接。那么我们可以把prices分成两部分,第一部分包含第一次交易,第二部分包含第二次交易, 每一部分就是求买卖一次情况下最大收益,即LeetCode121的解法。这样我们把分成两部分的所有情况都遍历一遍就可以得到结果了。

比如 [2,1,0,1,2],我们可以这样分

[2,1,0,1,2]

[2],[1,0,1,2]

[2,1] ,[0,1,2]

[2,1,0],[1,2]

[2,1,0,1] [2]

在上面五个组合中,一定至少有一个组合包含最优解。代码如下。

    static  private int getProfitOnce(int[] prices, int s, int e){
        int buy = prices[s];
        int maxProfit = 0;
        for(int i = s; i<=e; i++){
            buy = Math.min(prices[i], buy);
            maxProfit = maxProfit > prices[i]-buy? maxProfit: prices[i]-buy;
        }
        return maxProfit;
    }
    public static int maxProfit(int[] prices) {
        int maxProfit = 0;
        if(prices.length == 0) return 0;
        maxProfit = getProfitOnce(prices, 0, prices.length-1);
        for(int i=2; i<prices.length-1; i++){
            int first = getProfitOnce(prices, 0, i-1);
            int second = getProfitOnce(prices, i, prices.length-1);
            int profit = first + second;
            maxProfit = maxProfit > profit? maxProfit: profit;
        }
        return maxProfit;
    }

由于分组时间复杂度为O(N),每一组找最大值的时间复杂度也为O(N)。上面的代码总时间复杂度为O(N^2)。

可惜放到LeetCode里面跑,结果超时了。那么我们只能寻找更佳的解法了。

我们依然还是分组的思想,分组就是O(N)。但是我们知道求解一个分组的复杂度任然是O(N)。 如果嵌套就是O(N^2),但是如果是并列呢,并列就是O(N)+O(N),仍然是O(N)。那么可行吗,可行。

以分组点,假如两边的分组最大利润我们已经知道了,那么我们就可以知道该点分界产生的最大利润,遍历一遍分界点,就知道那个分界点产生最大利润。

那么我们现在就要求某点初前产生的最大利润和某点初最大的利润。某点初前产生的最大利润和LeetCode121是一样的,我们直接用就行啦。

那么分界点后面的怎么求呢,那么从右向左遍历,遍历过程中存储左边的最大值,最大值和当前值之差就是当前点之后进行一次交易的最大利润了。

这样我们通过三个遍历就可以求解了,代码如下。

static public int maxProfit2(int[] prices) {
        if(prices.length == 0) return 0;
        int leftBuy = prices[0];
        int leftMaxProfit = 0;
        int[] leftProfitArray = new int[prices.length];

        for(int i = 1; i< prices.length; i++){
            leftBuy = Math.min(prices[i], leftBuy);
            leftMaxProfit = leftMaxProfit > prices[i]-leftBuy? leftMaxProfit: prices[i]-leftBuy;
            leftProfitArray[i] = leftMaxProfit;
        }

        int rightBuy = prices[prices.length-1];
        int rightMaxProfit = 0;
        int[] rightProfitArray = new int[prices.length];
        for(int i = prices.length-2; i>=0 ;i --){
            rightBuy = Math.max(prices[i], rightBuy);
            rightMaxProfit = rightMaxProfit > rightBuy - prices[i]? rightMaxProfit:rightBuy-prices[i];
            rightProfitArray[i] = rightMaxProfit;
        }

        int maxProfit = 0;
        for(int i = 0; i < prices.length; i++){
            maxProfit = Math.max(maxProfit, leftProfitArray[i] + rightProfitArray[i]);
        }
        return maxProfit;
    }


时间和空间复杂度均为O(N)。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值