原题链接: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或者1,0代表不持有股票,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]