【LeetCode】Best Time to Buy and Sell Stock 程序员炒股 part.2

【题目】

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.

一个数组price[i]表示第i天股票的价格,你可以操作两次(进行两次买卖),求最大获利。

【解析】

又一道动态规划。

假设刚开始我一毛钱都没有。

第i天可以进行的操作有4种:

1. 前i天只进行一次买进操作。profit_Buy1Sell0[i]

毫无疑问这是亏本的。如果买进第i天的股票,则盈利为-price[i],如果不买第i天的股票,那么去“前i-1天只进行一次买进操作”的过程里去找对应的值profit_Buy1Sell0[i-1],比较-price[i]和profit_Buy1Sell0[i-1]的大小取较大者,即为该操作下的最大盈利(最小亏损),赋值给profit_Buy1Sell0[i]

即,

profit_Buy1Sell0[i]  =  max (  -price[i]  ,  profit_Buy1Sell0[i-1]  )


2. 前i天进行一次买进和一次卖出操作。profit_Buy1Sell1[i]

在第i天的时候,我有两种选择:

第一种,卖出当天的股票,前提是我手上已经有一支股票了,那么我就去“前i-1天只进行一次买进操作”的过程里取找对应的值profit_Buy1Sell0[i-1],接下来将前i-1天买到的那只股票卖掉,那么盈利为——  profit_Buy1Sell0[i-1]  +   price[i]

第二种,当天不进行操作,也就是说在前i-1天已经进行了一次买进和一次卖出的操作了。则此时盈利为:profit_Buy1Sell1[i-1]

比较以上两种操作方法,取最大值赋给profit_Buy1Sell1[i]

即,

  profit_Buy1Sell1[i]  = max (  profit_Buy1Sell0[i-1]  +   price[i]   ,   profit_Buy1Sell1[i-1]  )


3. 前i天进行两次买进和一次卖出操作。profit_Buy2Sell1[i]

同样到了第i天,我有两种两种选择:

买进当天的股票,或者不买。

同上,若买进,前i-1天就进行了一次买进和一次卖出,去找profit_Buy1Sell1[i-1],在减掉购买当天股票的成本,即为profit_Buy1Sell1[i-1]-price[i]。

若不买,则前i-1天已经完成了两次买进一次卖出的操作,去找profit_Buy2Sell1[i-1]。

取两者最大值赋给profit_Buy2Sell1[i]

即,

profit_Buy2Sell1[i]  =  max (  profit_Buy1Sell1[i-1]-price[i]  ,  profit_Buy2Sell1[i-1]  )


4. 前i天进行两次买进和两次次卖出操作。profit_Buy2Sell2[i]

到了这一步思路应当逐渐清晰,两种选择:

卖出当天股票,获益为profit_Buy2Sell1[i-1] + price[i]

不卖当天股票,获益为前i-1天进行两买两卖的获益,即profit_Buy2Sell2[i-1]

取两者最大值,即为:

profit_Buy2Sell2[i]  =  max  (  profit_Buy2Sell1[i-1] + price[i]   ,   profit_Buy2Sell2[i-1]  )


最后,比较profit_Buy1Sell1[i] 和 profit_Buy2Sell2[i] ,输出两者的较大值。

注:profit_Buy1Sell1[i] 若较大,是否是只进行了一次操作,从而与题意不符???

从讨论的结果看来,此题应该是考虑了当天买当天卖的这种情况,也合情合理,买卖一次就能利益最大化,为什么还要乱操作一通。。。


上述四种操作,编程的时候可以建立4个不同的数组,从0到i遍历price数组,将4个数组逐个填入对应数。

为减少空间复杂度,可以用current[0-3]和next[0-3]来保存当日操作的盈利数据。

【程序】

理解版:

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int len = prices.size();
        
        int profit_Buy1Sell0[len+1]={INT_MIN};
        int profit_Buy1Sell1[len+1]={0};
        int profit_Buy2Sell1[len+1]={INT_MIN};
        int profit_Buy2Sell2[len+1]={0};
        
        for(int i = 0; i<len; i++)
        {
            profit_Buy1Sell0[i+1] = max(profit_Buy1Sell0[i], -prices[i]);
            profit_Buy1Sell1[i+1] = max(profit_Buy1Sell0[i] + prices[i] , profit_Buy1Sell1[i]);
            profit_Buy2Sell1[i+1] = max(profit_Buy1Sell1[i] - prices[i] , profit_Buy2Sell1[i]);
            profit_Buy2Sell2[i+1] = max(profit_Buy2Sell1[i] + prices[i] , profit_Buy2Sell2[i]);
        }
        
        return max(profit_Buy1Sell1[len],profit_Buy2Sell2[len]);
    }
};

优化之后:

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int states[2][4] = {INT_MIN, 0, INT_MIN, 0}; // 0: 1 buy, 1: one buy/sell, 2: 2 buys/1 sell, 3, 2 buys/sells
        int len = prices.size(), i, cur = 0, next =1;
        for(i=0; i<len; ++i)
        {
            states[next][0] = max(states[cur][0], -prices[i]);
            states[next][1] = max(states[cur][1], states[cur][0]+prices[i]);
            states[next][2] = max(states[cur][2], states[cur][1]-prices[i]);
            states[next][3] = max(states[cur][3], states[cur][2]+prices[i]);
            swap(next, cur);
        }
        return max(states[cur][1], states[cur][3]);
    }


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值