LeetCode 309: 一个很清晰的DP解题思路

问题来源

题目来源链接见下方:
https://leetcode.com/problems/best-time-to-buy-and-sell-stock-with-cooldown/description/

问题简述:

假如有一个 i 个元素的数组,数组的每个元素表示了第 i 天某只股票的价格,设计一种算法来找到利润最大的买卖方式。设计的算法必须遵守以下两条约束条件:

  • 在一天当中,只能进行“买”,“卖”或者“什么都不干”中的一种操作
  • 在“卖”掉股票之后,必须“什么都不干”一天

举个例子:

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

解题思路

首先申明一下,这个思路并不是我想出来的,只是在LeetCode上看到有人这样解,觉得这个思路很不错,所以写下来作为分享和记录。
从题目中可以看出,不管哪一天,都只能是 buy 或者 sell 或者 cooldown(rest) 三种状态中的一种,而根据题目的约束条件,我们可以画出下图所示的状态图:
状态描述图

图1:状态描述图
由此图我们可以得到:
s0[i] = max(s0[i - 1], s2[i - 1])
s1[i] = max(s0[i - 1] - prices[i], s1[i - 1])
s2[i] = s1[i - 1] + prices[i]

其中s0,s1,s2分别表示三种状态下的最大利润值。
值得注意的是这里的s0,s1和s2不是单纯的buy,sell, rest,而应该是

s0 —— sell后rest或者rest后rest
s1 —— rest后的buy或者buy后的rest
s2 —— rest后的sell

同时,可以注意到的是,每次的状态 i 都只与前一次的状态 i - 1有关,也就是说我们可以把空间复杂度从O(n)降到O(1)。

解题代码

好了,话不多说,下面是时间复杂度为O(n),空间复杂度为O(1)的DP代码:

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        if (prices.size() <= 1)
            return 0;
        int s0 = 0;
        int s1 = -prices[0];
        int s2 = INT_MIN;
        for (int i = 1; i < prices.size(); i++){
            int pre0 = s0;
            int pre1 = s1;
            int pre2 = s2;
            s0 = max(pre0, pre2);
            s1 = max(pre0 - prices[i], pre1);
            s2 = pre1 + prices[i];
        }
        //最大利润不可能出现在buy而未sell的时候,所以不考虑s1
        return max(s0, s2);
    }
};

结束语

利用动态规划解题的难点在于要搞清楚有哪些状态,每个状态是怎么来的,之后就是把状态用代码写出来了。
如有错误,还请指正~

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

七元权

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值