[Leetcode] 123. 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).

思路

1、O(n)空间复杂度的动态规划:由于最多进行两次交易,所以第一次交易和第二次交易的分割点就比较关键。我们定义left_max[i]表示在[0, i]区间内完成一笔交易所能获得的最利润,而right_max[i]则表示在[i, prices.size() - 1]区间内完成一笔交易所能获得的最大利润。显然,left_max和right_max都可以通过线性扫描,采用贪心策略正确计算出来,最后线性扫描,取得最佳分割点即可。不过,最后别忘了将交易两次的获利和只交易一次的最大获利相比较,并取最大值(left_max[prices.size() - 1]或者right_max[0])。

2、O(1)空间复杂度的动态规划:可以交易两次,因此可以记录一下两次买和两次卖之后的最大利润。因为可以交易两次,所以第二次交易将会依赖于第一次的结果,即第二次买下一个股票剩下的利润依赖于之前第一次卖掉股票之后的利润——当前的股票价格。同理第二次卖掉一支股票之后剩下的利润依赖于第二次买下一支股票之后剩下的利润+当前的股票价格。注意,我们在这里其实也就是把买入一只股票当作了-prices[i]的收益。

代码

1、O(n)空间复杂度的动态规划:

class Solution {
public:
    int maxProfit(vector<int>& prices) 
    {
        if(prices.size() <= 1)
            return 0;
        vector<int> left_max(prices.size(), 0);
        vector<int> right_max(prices.size(), 0);
        int lowest_price = prices[0];
        for(int i = 1; i < prices.size(); ++i)
        {
            if(prices[i] < lowest_price)
                lowest_price = prices[i];
            left_max[i] = max(left_max[i - 1], prices[i] - lowest_price);
        }
        int highest_price = prices[prices.size() - 1];
        for(int i = prices.size() - 2; i >= 0; --i)
        {
            if(prices[i] > highest_price)
                highest_price = prices[i];
            right_max[i] = max(right_max[i + 1], highest_price - prices[i]);
        }
        int max_profit = 0;
        for(int i = 0; i < prices.size() - 1; ++i)
        {
            int sum_price = left_max[i] + right_max[i + 1];
            if(max_profit < sum_price)
                max_profit = sum_price;
        }
        return max(max_profit, right_max[0]);
    }
};

2、O(1)空间复杂度的动态规划:

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        if (prices.size() == 0) {
            return 0;
        }
        int buy1 = INT_MIN, buy2 = INT_MIN, sell1 = 0, sell2 = 0;
        for (auto it = prices.begin(); it != prices.end(); ++it) {
            buy1 = max(buy1, -*it);
            sell1 = max(sell1, buy1 + *it);
            buy2 = max(buy2, sell1 - *it);
            sell2 = max(sell2, buy2 + *it);
        }
        return sell2;
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值