LintCode 151 买卖股票的最佳时机 III

LintCode 151 买卖股票的最佳时机 III

今天做了两道动态规划的题目,感觉对动态规划有了更深入的了解。废话不多说,这是第一道。题目要求如下:

假设你有一个数组,它的第i个元素是一支给定的股票在第i天的价格。设计一个算法来找到最大的利润。你最多可以完成两笔交易。
注意事项
你不可以同时参与多笔交易(你必须在再次购买前出售掉之前的股票)

给出样例如下:

给出一个样例数组 [4,4,6,1,1,4,2,5],返回 6

题目给出的框架如下:

class Solution {
public:
    /**
     * @param prices: Given an integer array
     * @return: Maximum profit
     */
    int maxProfit(vector<int> &prices) {
        // write your code here
    }
};

解题思路

一开始的想法是用两个数组buy[]和sell[]来解决,状态转移方程为:

buy[i] = max(buy[i-1],sell[i-1] - prices[i])
sell[i] = max(sell[i-1],buy[i-1] + prices[i])

最后返回sell[len-1],其中 i 为当前天数,len为总共的天数。

想法很简单,将当前状态分为已经买入股票和已经卖出股票这两种:

1. 如果第 i 天的状态为买入股票的话, 要么就是之前买了股票,第i天不买,对应于buy[i-1];要么就是之前卖了股票,第i天买入股票,对应于sell[i-1] - prices[i])

2. 同理, 如果第 i天的状态为卖出股票的话,要么就是之前卖了股票,第i天不卖,对应于sell[i-1];要么就是之前买了股票,第i天卖掉,对应于buy[i-1]+ prices[i]

但这忽视了一个条件:

你最多可以完成两笔交易!

因此,上面的状态转移方程解决的问题应该是 :

不管你交易多少笔,你的最大获利是多少!

这是因为你没有限制交易多少笔,所以只要能获利,我就可以将交易增加到3次,4次甚至更多次,sell[len]的值也会相应的增加。

那如何限制交易的次数为2呢?

既然你说只能交易两次,那么我就对buysell两次交易分别用两个数组存不就行了?!说做就做,状态转移方程如下:

firstBuy[i] = max(firstBuy[i - 1], -prices[i])

firstSell[i] = max(firstSell[i - 1], firstBuy[i - 1] + prices[i])

secondBuy[i] = max( secondBuy[i - 1], firstSell[i - 1] - prices[i])

secondSell[i] = max( secondSell[i - 1], secondBuy[i - 1] + prices[i])

方程很好理解:

1. 如果第 i 天为第一次买的状态,要么就是之前买过了,第i天不卖,对应于firstBuy[i -1],要么就是之前没有买,第i天买入股票,对应于-prices[i]

2. 如果第 i 天为第一次卖的状态,要么就是之前卖出了,第i天不买,对应于firstSell[i -1],要么就是之前买入了股票,第i天卖出股票,对应于firstBuy[i - 1] + prices[i]

3. 如果第 i 天为第二次买的状态,要么就是之前已经二次买过了,第i天不卖,对应于secondBuy[i -1],要么就是之前卖过一次了,第i天再次买入股票,对应于firstSell[i - 1] - prices[i]

4. 如果第 i 天为第二次卖的状态,要么就是之前已经二次卖过了,第i天不买,对应于secondSell[i -1],要么就是之前第二次购买,第i天卖出股票,对应于secondBuy[i - 1] + prices[i]

最后,还需要对第一天的买卖进行初始化:

firstBuy[0] = -prices[0]

secondBuy[0] = -prices[0]

firstSell[0] = 0

secondSell[0] = 0

代码实现

代码实现如下:

class Solution {
public:
    /**
     * @param prices: Given an integer array
     * @return: Maximum profit
     */
    int maxProfit(vector<int> &prices) {
        // write your code here
        const int len = prices.size();
        if (len == 0)
            return 0;
        int firstBuy[len];
        int secondBuy[len];
        int firstSell[len];
        int secondSell[len];
        firstBuy[0] = -prices[0];
        secondBuy[0] = -prices[0];
        firstSell[0] = 0;
        secondSell[0] = 0;
        for (int i = 1; i < len; ++i) {
            firstBuy[i] = max(firstBuy[i - 1], -prices[i]);
            firstSell[i] = max(firstSell[i - 1], firstBuy[i - 1] + prices[i]);
            secondBuy[i] = max(secondBuy[i - 1], firstSell[i - 1] - prices[i]);
            secondSell[i] = max(secondSell[i - 1],
                    secondBuy[i - 1] + prices[i]);
        }
        return secondSell[len - 1];
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值