123/188/309.Best Time to Buy and Sell Stock 买股票的最佳时间

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

原题链接: http://oj.leetcode.com/problems/best-time-to-buy-and-sell-stock-iii/
这道题是Best Time to Buy and Sell Stock的扩展,现在我们最多可以进行两次交易。我们仍然使用动态规划来完成,事实上可以解决非常通用的情况,也就是最多进行k次交易的情况。
这里我们先解释最多可以进行k次交易的算法,然后最多进行两次我们只需要把k取成2即可。我们还是使用“局部最优和全局最优解法”。我们维护两种量,一个是当前到达第i天可以最多进行j次交易,最好的利润是多少(global[i][j]),另一个是当前到达第i天,最多可进行j次交易,并且最后一次交易在当天卖出的最好的利润是多少(local[i][j])。下面我们来看递推式,全局的比较简单,
global[i][j]=max(local[i][j],global[i-1][j]),
也就是去当前局部最好的,和过往全局最好的中大的那个(因为最后一次交易如果包含当前天一定在局部最好的里面,否则一定在过往全局最优的里面)。对于局部变量的维护,递推式是
local[i][j]=max(global[i-1][j-1]+max(diff,0),local[i-1][j]+diff),
也就是看两个量,第一个是全局到i-1天进行j-1次交易,然后加上今天的交易,如果今天是赚钱的话(也就是前面只要j-1次交易,最后一次交易取当前天),第二个量则是取local第i-1天j次交易,然后加上今天的差值(这里因为local[i-1][j]比如包含第i-1天卖出的交易,所以现在变成第i天卖出,并不会增加交易次数,而且这里无论diff是不是大于0都一定要加上,因为否则就不满足local[i][j]必须在最后一天卖出的条件了)。
上面的算法中对于天数需要一次扫描,而每次要对交易次数进行递推式求解,所以时间复杂度是O(n*k),如果是最多进行两次交易,那么复杂度还是O(n)。空间上只需要维护当天数据皆可以,所以是O(k),当k=2,则是O(1)。代码如下:

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        return slover(prices, 2);
    }

    int slover(vector<int>& prices, int k) {
        if(prices.empty()) return 0;
        int n = prices.size();
        int g[n][k+1] = {};             // g[n][k+1]={0}的初始方式不能AC,原因待查。
        int l[n][k+1] = {};
        for(int i = 1; i < n; ++i) {
            int diff = prices[i] - prices[i-1];
            for(int j = 1; j <= k; ++j) {     //状态转移方程,l和g用以区分第i天是否出售股票。
                l[i][j] = max(g[i-1][j-1]+max(0,diff), l[i-1][j] + diff);
                g[i][j] = max(l[i][j], g[i-1][j]);
            }
        }
        return g[n-1][k];
    }
};

笔记:很好的DP题,只能看懂、

188.Best Time to Buy and Sell Stock IV 买卖股票的最佳时间之四

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 k transactions.

Note:
You may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again).

Credits:
Special thanks to @Freezen for adding this problem and creating all test cases.
这道题实际上是之前那道 Best Time to Buy and Sell Stock III 买股票的最佳时间之三的一般情况的推广,还是需要用动态规划Dynamic programming来解决,但这道题还有个坑,就是如果k的值远大于prices的天数,比如k是好几百万,而prices的天数就为若干天的话,上面的DP解法就非常的没有效率,应该直接用Best Time to Buy and Sell Stock II 买股票的最佳时间之二的方法来求解,所以实际上这道题是之前的二和三的综合体,代码如下:

class Solution {
public:
    int maxProfit(int k, vector<int>& prices) {
        if(prices.empty()) return 0;
        int n = prices.size();

        if(k >= n-1) return slover(prices);  //分类讨论,选择最简单的求解模型

        int g[n][k+1] = {};             // g[n][k+1]={0}的初始方式不能AC,原因待查。
        int l[n][k+1] = {};
        for(int i = 1; i < n; ++i) {
            int diff = prices[i] - prices[i-1];
            for(int j = 1; j <= k; ++j) {     //状态转移方程,l和g用以区分第i天是否出售股票。
                l[i][j] = max(g[i-1][j-1]+max(0,diff), l[i-1][j] + diff);
                g[i][j] = max(l[i][j], g[i-1][j]);
            }
        }
        return g[n-1][k];
    }

    int slover(vector<int>& prices) {
        int res = 0;
        int n = prices.size();
        for(int i = 1; i < n; ++i) {
            if(prices[i] > prices[i-1])
                res += prices[i] - prices[i-1];
        }
        return res;
    }
};

笔记:分类讨论,选择最简单的求解模型。

309 Best Time to Buy and Sell Stock with Cooldown

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 as many transactions as you like (ie, buy one and sell one share of the stock multiple times) with the following restrictions:

  • You may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again).
  • After you sell your stock, you cannot buy stock on next day. (ie, cooldown 1 day)

Example:

prices = [1, 2, 3, 0, 2]
maxProfit = 3
transactions = [buy, sell, cooldown, buy, sell]

Credits:
Special thanks to @dietpepsi for adding this problem and creating all test cases.

这题比Best Time to Buy and Sell Stock II多了一个cooldown的条件,就变得麻烦多了。这题是一个多阶段优化问题,首先范围缩小到广搜,贪心或者动规。因为每步之间互相牵连,贪心显然不行。广搜固然可以,不过是O(2^n)复杂度,所以我们先考虑用动规。
对于每一天,有三种动作,buy, sell, cooldown, sell 和 cooldown 可以合并成一种状态,因为手里最终没有股票。最终需要的结果是 sell,即手里股票卖了获得最大利润。我们可以用两个数组来记录当前持股和未持股的状态,令sell[i] 表示第i天未持股时,获得的最大利润,buy[i]表示第i天持有股票时,获得的最大利润。
对于sell[i],最大利润有两种可能,一是今天没动作跟昨天未持股状态一样,二是今天卖了股票,所以状态转移方程如下:
sell[i] = max{sell[i - 1], buy[i-1] + prices[i]}
对于buy[i],最大利润有两种可能,一是今天没动作跟昨天持股状态一样,二是前天卖了股票,今天买了股票,因为 cooldown 只能隔天交易,所以今天买股票要追溯到前天的状态。状态转移方程如下:
buy[i] = max{buy[i-1], sell[i-2] - prices[i]}+

最终我们要求的结果是sell[n - 1],表示最后一天结束时,手里没有股票时的最大利润。

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        if(prices.empty()) return 0;
        int n = prices.size();
        int buy[n+1] = {};
        int sell[n+1] = {};

        buy[0] = -prices[0];    //初始化

        for(int i = 1; i < n; ++i) {
            sell[i] = max(sell[i-1], buy[i-1] + prices[i]);
            buy[i] = max(buy[i-1], i == 1 ? -prices[i] : sell[i-2] - prices[i]); //注意边界问题,当i=1,sell[i-2]不存在,应自己给出其值为0.
        }
        return sell[n-1];
    }
};

笔记:DP问题,注意初始化条件、状态转移方程、特殊情况的分类讨论。
这里写图片描述
rest[i] = max(sell[i-1], rest[i-1]) 说明rest前面只可能出现rest和sell.即排除[buy, rest, buy]这种情况。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值