LeetCode 309 Best Time to Buy and Sell Stock with Cooldown

LeetCode 309 Best Time to Buy and Sell Stock with Cooldown

题意

给出一串数组prices,数组中第i个元素代表第i天股票的价格,每天你可以选择购入一张股票或者售出已有股票,但有如下要求:

  • 你不能同时参与多个交易,即当你手中有一张股票时你只能在卖出之后才能再次购入股票
  • 售出股票后你必须等待一天才能继续购入

设计一个算法使受益最大。

思路

每天可选择购入或售出,尽管有限制条件,但仍然是阶段决策任务,可以采用动态规划。不妨假设取得最大收益p时第n售出了股票,第n-1购入了股票,那么可以肯定的是,第n-1天在购入股票(或者说拥有一张股票)的情况下最大收益一定是p-price[n],即最优解可以由子问题的最优解得到,也就是说可以通过动态规划的方式计算最大收益,那么我们来定义子结构 - 状态数组。
一种方法是定义(也是我最初的思路)
dp[i][3]=第i天 购入/售出/无操作 时前i天利益最大值
但是这种方法无法区分既不购入也不售出(无操作)冷却时间这两种情况,因为处于冷却时间时也是无操作。所以应当以拥有的股票数定义:
dp[i][3]=第i天拥有 无股票无操作/售出股票/持有一张股票 股票时前i天利益最大值
实际上,第i天在执行完对应的操作后,前两种情况股票数为0,第三种情况下股票数为1。
状态转移方程:

dp[i][无股票无操作] = max(dp[i - 1][无股票无操作], dp[i - 1][售出股票]);
dp[i][售出股票] = dp[i - 1][有一张股票] + prices[i];
dp[i][有一张股票] = max(dp[i - 1][无股票无操作] - prices[i], dp[i - 1][有一张股票]);

这样即可通过遍历得到最后一天三种情况下的收益。

P.S. 因为dp[i]只与dp[i-1]有关,因此可以压缩为dp[2][3],通过0和1表示i-1

代码

class Solution {
  public:
    int maxProfit(vector<int> &prices) {
        const int n = prices.size();
        if (n <= 0)
            return 0;
        int dp[n + 1][3] = {};
        dp[1][2] = -prices[0];
        for (int i = 2; i <= n; i++) {
            int pi = i - 1;
            dp[i][0] = max(dp[i - 1][0], dp[i - 1][1]);
            dp[i][1] = dp[i - 1][2] + prices[pi];
            dp[i][2] = max(dp[i - 1][0] - prices[pi], dp[i - 1][2]);
        }
        int res = 0;
        for (int i = 0; i < 3; i++)
            res = max(res, dp[n][i]);
        return res;
    }
};

总结

多段决策任务往往可以通过动态规划的方法解决,但子结构与状态转移方程是解题的关键。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值