1、LeetCode123买卖股票的最佳时机III
题目链接:123、买卖股票的最佳时机III
本题要求至多买卖两次,这意味着可以买卖一次,可以买卖两次,也可以不买卖。
一天一共有5个状态
0:没有操作
1:第一次持有股票
2:第一次不持有股票
3:第二次持有股票
4:第二次不持有股票
1、dp[i][j]中 i表示第i天,j为 [0 - 4] 五个状态,dp[i][j]表示第i天状态j所剩最大现金。
2、递推公式:
达到dp[i][1]状态,有两个具体操作:
操作一:第i天买入股票了,那么dp[i][1] = dp[i-1][0] - prices[i]
操作二:第i天没有操作,而是沿用前一天买入的状态,即:dp[i][1] = dp[i - 1][1]
同理dp[i][2]也有两个操作:
操作一:第i天卖出股票了,那么dp[i][2] = dp[i - 1][1] + prices[i]
操作二:第i天没有操作,沿用前一天卖出股票的状态,即:dp[i][2] = dp[i - 1][2]
同理可推出剩下状态部分:
dp[i][3] = max(dp[i - 1][3], dp[i - 1][2] - prices[i]);
dp[i][4] = max(dp[i - 1][4], dp[i - 1][3] + prices[i]);
3、初始化:
第0天没有操作,这个最容易想到,就是0,即:dp[0][0] = 0;
第0天做第一次买入的操作,dp[0][1] = -prices[0];
第0天做第一次卖出的操作,可以理解当天买入,当天卖出,所以dp[0][2] = 0;
第0天第二次买入操作,相当于第0天第一次买入了,第一次卖出了,然后再买入一次,dp[0][3] = -prices[0];
同理第二次卖出初始化dp[0][4] = 0;
4、遍历顺序:从前向后。
5、举例推导。
class Solution {
public:
int maxProfit(vector<int>& prices) {
if (prices.size() == 0) return 0;
vector<vector<int>> dp(prices.size(), vector<int>(5, 0));
dp[0][0] = 0;
dp[0][1] = -prices[0];
dp[0][2] = 0;
dp[0][3] = -prices[0];
dp[0][4] = 0;
for (int i = 1; i < prices.size(); i++)
{
dp[i][0] = dp[i-1][0];
dp[i][1] = max(dp[i-1][1], dp[i-1][0] - prices[i]);
dp[i][2] = max(dp[i-1][2], dp[i-1][1] + prices[i]);
dp[i][3] = max(dp[i-1][3], dp[i-1][2] - prices[i]);
dp[i][4] = max(dp[i-1][4], dp[i-1][3] + prices[i]);
}
return dp[prices.size()-1][4];
}
};
2、LeetCode188买卖股票的最佳时机IV
题目链接:188、买卖股票的最佳时机IV
1、使用二维数组 dp[i][j] :第i天的状态为j,所剩下的最大现金是dp[i][j]
每天状态为:
0:没有操作
1:第一次持有股票
2:第一次不持有股票
3:第二次持有股票
4:第二次不持有股票
......
本题至多可以买卖k次,每买卖一次,都对应了两天的状态,即第一天买入第二天卖出。
奇数买入偶数卖出。
所以 j 的范围一共可以有 2 * k + 1, 下标从0开始 最大达到2 * k。
2、递推公式:
上一题的递推公式为:
dp[i][1] = max(dp[i-1][1], dp[i-1][0] - prices[i]);
dp[i][2] = max(dp[i-1][2], dp[i-1][1] + prices[i]);
dp[i][3] = max(dp[i-1][3], dp[i-1][2] - prices[i]);
dp[i][4] = max(dp[i-1][4], dp[i-1][3] + prices[i]);
本题奇数买入,偶数卖出。
for (int j = 0; j < 2 * k; j += 2)
{
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]);
}
3、初始化:
dp[0][j]当j为奇数的时候都初始化为 -prices[0];
4、遍历顺序:从前向后。
5、举例推导。
class Solution {
public:
int maxProfit(int k, vector<int>& prices) {
if (prices.size() == 0) return 0;
vector<vector<int>> dp(prices.size(), vector<int>(2 * k + 1, 0));
for (int i = 1; i < 2 * k; i += 2)
{
dp[0][i] = -prices[0];
}
for (int i = 1; i < prices.size(); i++)
{
for (int j = 0; j < 2 * k; j += 2)
{
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[prices.size() - 1][2 * k];
}
};