309. 最佳买卖股票时机含冷冻期

解体思路

官方题解

  1. 约束条件很多

    • 卖出股票只能在买入股票之后。
    • 卖出股票后需要等一天内才能继续买入股票。
    • 如果把卖出当作两天,需要对最后一天的卖出进行特殊的操作,这十分的麻烦。
  2. 解决这种复杂的问题一般采用动态规划(经验所致),状态确定了转移方程都不难,难的是确定状态

    • 如何确定状态?
    • d p [ i ] [ j ] dp[i][j] dp[i][j]代表啊第一次买入在第 i i i天,最后一次卖出在第 j j j天可不可以?产生问题:卖出股票后需要等一天才能继续买入怎么考虑进?如何糅合入 p r i c e s [ i ] prices[i] prices[i]这个东西?这种状态不好。
    • 于是我们考虑,既然约束条件十分的复杂,为什么我们不把约束条件放到我们的状态中?
  3. 考虑将约束条件糅合进我们的状态中:

    • 什么状态?

    • d p [ i ] dp[i] dp[i]代表第 i i i天结束后我们手头的最大的收入?

    • i i i天结束后我们有好几种状态?怎么考虑到这个的?因为这个卖出后还要等一天的设定,造成了很多的状态,这个是在是太麻烦了,所以我们把它拆分出来考虑。

    • 那么有:

    • d p [ i ] [ 0 ] dp[i][0] dp[i][0]代表第 i i i天结束后我们手头有股票的最大收入。

    • d p [ i ] [ 1 ] dp[i][1] dp[i][1]代表第 i i i天结束后我们手头没有股票且处于冻结期的最大收入。

    • d p [ i ] [ 2 ] dp[i][2] dp[i][2]代表第 i i i天结束后我们手头没有股票且不处于冻结期的最大收入。

    • 有了这个状态,我们的状态转移实在是太简单了!有一个需要注意的是,我们的状态的规定是一个累计的东西,我们得到第 i i i天的东西只需要从第 i − 1 i-1 i1天去得到,不需要考虑前面的 i − 2 , i − 3 , . . . i-2,i-3,... i2,i3,...等等的东西,因为 i i i天的状态可以从第 i − 1 i-1 i1天丝滑的过度过来。

    • 那么写下状态转移方程:

      d p [ i ] [ 0 ] = m a x ( d p [ i − 1 ] [ 2 ] − p r i c e s [ i ] , d p [ i − 1 ] [ 0 ] ) dp[i][0]=max(dp[i-1][2]-prices[i],dp[i-1][0]) dp[i][0]=max(dp[i1][2]prices[i],dp[i1][0])

      d p [ i ] [ 1 ] = d p [ i − 1 ] [ 0 ] + p r i c e s [ i ] dp[i][1]=dp[i-1][0]+prices[i] dp[i][1]=dp[i1][0]+prices[i]

      d p [ i ] [ 2 ] = m a x ( d p [ i − 1 ] [ 1 ] , d p [ i − 1 ] [ 2 ] ) dp[i][2]=max(dp[i-1][1],dp[i-1][2]) dp[i][2]=max(dp[i1][1],dp[i1][2])

    • 初始状态三个:

      d p [ 0 ] [ 2 ] = 0 ; 第 一 天 结 束 后 不 持 有 股 票 且 处 于 非 冷 冻 期 dp[0][2]=0; 第一天结束后不持有股票且处于非冷冻期 dp[0][2]=0;

      d p [ 0 ] [ 0 ] = − p r i c e s [ 0 ] ; 第 一 天 结 束 后 持 有 股 票 dp[0][0]=-prices[0]; 第一天结束后持有股票 dp[0][0]=prices[0];

      d p [ 0 ] [ 1 ] = 0 ; 第 一 天 结 束 后 不 持 有 有 股 票 且 处 于 冷 冻 期 dp[0][1]=0; 第一天结束后不持有有股票且处于冷冻期 dp[0][1]=0;

class Solution {
public:
    int dp[10005][3];
    int maxProfit(vector<int>& prices) {
        int n=prices.size();
        /*
        * 这句话需要些,被坑一次
        */
        if(n==0){
            return 0;
        }
        dp[0][2]=0;         // 第一天结束后不持有股票且处于非冷冻期
        dp[0][0]=-prices[0]; // 第一天结束后持有股票
        dp[0][1]=0;         // 第一天结束后不持有有股票且处于冷冻期
        for(int i=1;i<n;i++){
            // 第i天结束后持有股票,可能
            // 1. 由第i-1天结束后持有股票转化
            // 2. 由低i-1天结束后不持有股票但是第i天购买了股票转化而来
            dp[i][0]=max(dp[i-1][2]-prices[i],dp[i-1][0]);
            // 第i天结束后不持有股票,处于冷冻期
            // 1. 第i-1天结束后持有股票,第i天卖掉了股票转化而来
            dp[i][1]=dp[i-1][0]+prices[i];
            // 第i天结束后不持有股票,不处于冷冻期
            // 1. 第i-1天结束后不持有股票,处于冷冻期转化而来
            // 2. 第i-1天结束后不持有股票,不处于冷冻期转化而来
            dp[i][2]=max(dp[i-1][1],dp[i-1][2]);
        }   
        int res=max(dp[n-1][1],dp[n-1][2]);
        printf("%d\n",res);
        return res; 
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值