leetcode算法题--最佳买卖股票时机含冷冻期★

原题链接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-cooldown/

一开始用普通的动态规划做,思路是:

dp[i]=dp[j]+j到i之间数的最大差

一般动态规划用这种方法也可行,但是这里的边界判断真的把我想吐了。当i<=3的时候,这些数是可以直接计算的,因为不符合间隔的条件。或者当j=0的时候,也是可以直接计算,其余的情况需要间隔一个。

 int maxProfit(vector<int>& prices) {
     if(prices.empty()) return 0;
     int len=prices.size();
     if(len==1) return 0;
     vector<int> dp(len,0);
     vector<vector<int>> sub(len,vector<int>(len,0));
     for(int i=0;i<len;i++){
         for(int j=0;j<i;j++){
             sub[i][j]=std::max(sub[i][j],prices[i]-prices[j]);
         }
     }
     for(int i=1;i<len;i++){
         for(int j=0;j<i;j++){
             if(j==0||i<3){
                 dp[i]=max(dp[i],dp[j]+sub[i][j]);
             }else{
                 if(j+2>i) break;
                 dp[i]=max(dp[i],dp[j]+sub[i][j+2]);
             }
         }
     }
     return dp[len-1];
 }

但是这种方法会超时,看了题解之后有更好的动态规划方法。

dp[i][j]代表第i天,j取值为0或者10代表不持有股票,1代表持有股票

于是有

dp[i][0]=max(dp[i-1][0],dp[i-1][1]+prices[i])//要么是前一天的状态,要么是前一天持有今天卖出
dp[i][1]=max(dp[i-1][1],dp[i-2][0]-prices[i])//要么是前一天的状态,要么是两天前卖出,今天买入

这里有个问题就是dp[i-2][0]其实不一定代表是第i-2天一定卖出,也可能是不持有状态的延续,所以是不是有问题呢?

这里leetcode上一个用户的解释比较好理解:

没有“冷冻期”的DPtable如下式:

dp[i][0] = max(dp[i-1][0], dp[i-1][1] + prices[i])
dp[i][1] = max(dp[i-1][1], dp[i-1][0] - prices[i])

添加“冷冻期”条件后,dp[i-1][0] - prices[i]代表的“i-1天买入”不一定能成立,要再判断“i-2天是否存在卖出行为”

所以进一步拆解dp[i-1][0]

dp[i-1][0] = max(dp[i-2][0], dp[i-2][1] + prices[i])
dp[i][1] = max(dp[i-1][1], max(dp[i-2][0], dp[i-2][1] + prices[i]) - prices[i])

其中dp[i-2][1] + prices[i]代表着“i-2发生了卖出行为”,有违题意,应予删除,得下式:

dp[i][1] = max(dp[i-1][1], max(dp[i-2][0]) - prices[i])

代码:

int maxProfit(vector<int>& prices) {
    int n=prices.size();
    if(n==0||n==1) return 0;
    vector<vector<int>> dp(n,vector<int>(2,0));
    dp[0][0]=0;
    dp[0][1]=-prices[0];
    dp[1][0]=max(0,prices[1]-prices[0]);
    dp[1][1]=max(-prices[0],-prices[1]);  
    for(int i=2;i<n;i++){
        dp[i][0]=max(dp[i-1][0],dp[i-1][1]+prices[i]);
        dp[i][1]=max(dp[i-1][1],dp[i-2][0]-prices[i]);
    }
    return dp[n-1][0];
}

简化:

int maxProfit(vector<int>& prices) {
    int len=prices.size();
    int dp_i_0=0,dp_i_1=INT_MIN,dp_pre_0=0;
    int tmp;
    for(int i=0;i<len;i++){
        tmp=dp_i_0;
        dp_i_0=max(dp_i_0,dp_i_1+prices[i]);
        dp_i_1=max(dp_i_1,dp_pre_0-prices[i]);
        dp_pre_0=tmp;
    }
    return dp_i_0;
}

使用dp_i_0,dp_i_1,dp_pre_0这些是为了循环从0开始并且方便存储dp[i-2][0]

参考链接:
https://github.com/labuladong/fucking-algorithm/blob/master/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92%E7%B3%BB%E5%88%97/%E5%9B%A2%E7%81%AD%E8%82%A1%E7%A5%A8%E9%97%AE%E9%A2%98.md

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值