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


只能进行两次股票交易的问题。

解法一

这个问题可以转换成Best Time to Buy and Sell Stock I问题。

两次股票交易的核心是可以定义一个交易点,在这个交易点之前可以做一次交易(赚的最大数目的钱为firstProf),在这个交易点之后可以做一个交易(赚的最大数目的钱是secondProf)。那么要求的是max(firstProf+secondProf)。但是这个方法的时间复杂度是O(N^2),空间复杂度是O(1)。leetcode中显示超时。

可以使用两次扫描的方法避免上面的双重循环。

不同于Best Time to Buy and Sell Stock I中定义的初始状态A[i]表示第i天卖出挣的最大数目的钱,这个更进一步直接定义A[i]表示前i天赚的最大数目的钱。minPrice表示从第0天到第i-1天中的最低价格。

A[0]=0。(初始状态)

A[1]=max(prices[1]-prices[0],A[0])

A[2]=max(prices[2]-minPrice,A[1])

.....

即A[i]=max(price[i]-minPrice,A[i-1]).

A[0]=0

另外一次扫描从数组后向前扫描,定义B[i]表示从第i天到最后一天n能赚的最大数目的钱。maxPrice表示第i+1天到n天的最高价格。

B[n]=0。(初始状态)

B[n-1]=max(maxPrice-prices[n-1],B[n])

B[n-2]=max(maxPrice-prices[n-2],B[n-1])

.....

即B[i]=max(maxPrice-prices[i],B[i+1])

B[n]=0

那么以第i天为分割点能赚的最多数目的钱为A[i]+B[i]

问题的解为max{A[i]+B[i]}。0<=i<=n。

时间复杂度是O(N),空间复杂度是O(N)。

runtime:12ms

class Solution {  
public:  
    int maxProfit(vector<int>& prices) {  
        int length=prices.size();  
        if(length==0||length==1)  
            return 0;  
  
        int * ascandMax=new int[length]();  
        int minPrice=prices[0];  
        int maxProf=0;  
        for(int i=1;i<length;i++)  
        {  
            maxProf=max(maxProf,prices[i]-minPrice);  
            minPrice=min(minPrice,prices[i]);  
            ascandMax[i]=maxProf;  
        }  
          
        int* descandMax=new int[length]();  
        int maxPrice=prices[length-1];  
        maxProf=0;  
        for(int i=length-2;i>=0;i--)  
        {  
            maxProf=max(maxProf,maxPrice-prices[i]);  
            maxPrice=max(maxPrice,prices[i]);  
            descandMax[i]=maxProf;  
        }  
          
        maxProf=0;  
        for(int i=0;i<length;i++)  
        {  
            maxProf=max(maxProf,ascandMax[i]+descandMax[i]);  
        }  
          
        delete [] ascandMax;  
        delete [] descandMax;  
        return maxProf;  
    }  
  
};  

解法二

在Discuss中看到一种很棒的解法,代码只有10行左右,但是不是很好理解。

第二种解法的核心是假设手上最开始只有0元钱,那么如果买入股票的价格为price,手上的钱需要减去这个price,如果卖出股票的价格为price,手上的钱需要加上这个price。

它定义了4个状态:

Buy1[i]表示前i天做第一笔交易买入股票后剩下的最多的钱;

Sell1[i]表示前i天做第一笔交易卖出股票后剩下的最多的钱;

Buy2[i]表示前i天做第二笔交易买入股票后剩下的最多的钱;

Sell2[i]表示前i天做第二笔交易卖出股票后剩下的最多的钱;

那么Sell2[i]=max{Sell2[i-1],Buy2[i-1]+prices[i]}

       Buy2[i]=max{Buy2[i-1],Sell[i-1]-prices[i]}

       Sell1[i]=max{Sell[i-1],Buy1[i-1]+prices[i]}

       Buy1[i]=max{Buy[i-1],-prices[i]}

可以发现上面四个状态都是只与前一个状态有关,所以可以不使用数组而是使用变量来存储即可。

这是leetcode中的讨论网址:https://leetcode.com/discuss/18330/is-it-best-solution-with-o-n-o-1

runtime:8ms

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int buy1 = INT_MIN, sell1 = 0, buy2 = INT_MIN, sell2 = 0;
        计算每次操作后赚钱最多
        for(int i = 0; i < prices.size(); i++) {
            buy1 = max(buy1, -prices[i]);
            ///第一次买后  因为是花钱,所以赚了 -prices[i]元 ,要选出花钱最少的那天买
            sell1 = max(sell1, buy1 + prices[i]);
            //第一次卖后  赚的钱
            buy2 = max(buy2, sell1 - prices[i]);
            //第二次买 ,买后赚的钱数为 第一次赚的 - 第二次买花的
            sell2 = max(sell2, buy2 + prices[i]);
            // 同第一次卖
        }
        return sell2;
    }
};

转自: http://blog.csdn.net/u012501459/article/details/46514309(加了一点自己的理解)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值