代码随想录训练营Day50 | Leetcode 123、188
一、123 买卖股票的最佳时机III
题目链接:123 买卖股票的最佳时机III
核心:限定了最多交易的次数是2,那么每个元素最多可存在的状态有4个:第一次持有&不持有,第二次持有&不持有(由于无需处理的状态均为0,故该状态可忽略),针对这四个不同状态求解其递推公式,然后遍历数组各元素得到各元素4个状态的dp数组。
第一,dp[i][0]:第i天第一次持有股票所得的现金,要么第i-1天已持有股票,要么第i天买入,且是第一次买入;
第二,dp[i][1]:第i天第一次不持有股票所得的现金,要么第i-1天已不持有股票,要么第i天卖出(隐含第i-1天是持有的);
第三,dp[i][2]:第i天第二次持有股票所得的现金,要么第i-1天已经第二次持有,要么第i天第二次买入(隐含第i-1天已经第一次不持有);
第四,dp[i][3]:第i天第二次不持有股票所得的现金,要么第i-1天已不持有,要么第i天卖出(第i-1天是第二次持有股票)。
int maxProfit(vector<int>& prices) {
//动态规划:限定最多2次,因此每个元素可能有4种状态:第一次持有/不持有,第二次持有/不持有
int len=prices.size();
if(len==0) return 0;
vector<vector<int>> dp(len,vector<int>(4)); //也可以增加一个不处理的状态
dp[0][0]=-prices[0]; //第一次持有(存在买入)
dp[0][1]=0; //第一次不持有(存在卖出)
dp[0][2]=-prices[0]; //第二次持有(第一个元素已经被买卖一次)(存在买入)
dp[0][3]=0; //第二次不持有(存在卖出)
for(int i=1;i<len;++i)
{
dp[i][0]=max(dp[i-1][0],-prices[i]); //要么i-1天已持有,要么i天买入
dp[i][1]=max(dp[i-1][1],dp[i-1][0]+prices[i]); //要么i-1天已不持有,要么i天卖出
dp[i][2]=max(dp[i-1][2],dp[i-1][1]-prices[i]); //i天第二次买入时i-1天必然是第一次不持有的状态,否则第一次持有时不能买入
dp[i][3]=max(dp[i-1][3],dp[i-1][2]+prices[i]); //第i天第二次卖出时i-1天必然是持有
}
return dp[len-1][3]; //最终利润最大值一定是第二次不持有的状态
}
二、188 买卖股票的最佳时机IV
题目链接:188 买卖股票的最佳时机IV
核心:最多交易的次数增加到k次,那么每个元素可存在的状态有2k个,再加上一个无需处理的状态(dp[i][0]),一共有2k+1个状态,可定义一个列数维度为2*k+1的数组。
令奇数为第j次持有股票所得的现金,比如:dp[i][1],dp[i][3]等,则偶数就是相对应的第j次不持有股票所得的现金。
第一,奇数时(持有股票),要么第i-1天已持有,要么第i天买入;
第二,偶数时(不持有股票),要么第i-1天已不持有,要么第i天卖出。
int maxProfit(int k, vector<int>& prices) {
//动态规划,由于交易最多是k次,那么可能存在2*k次不同状态,另加上一个无需处理的状态
int len=prices.size();
if(len==0) return 0;
vector<vector<int>> dp(len,vector<int>(2*k+1,0));
for(int j=1;j<2*k+1;j+=2)
dp[0][j]=-prices[0]; //奇数表示第j次持有(存在买入)
for(int i=1;i<len;++i)
{//遍历元素
for(int j=0;j<2*k-1;j+=2)
{//遍历交易的第j次
dp[i][j+1]=max(dp[i-1][j+1],dp[i-1][j]-prices[i]); //奇数(持有),买入
dp[i][j+2]=max(dp[i-1][j+2],dp[i-1][j+1]+prices[i]); //偶数(不持有),卖出
}
}
return dp[len-1][2*k];
}

3772

被折叠的 条评论
为什么被折叠?



