今天写动态规划的经典问题——股票问题,还是直接上例子。
买卖股票的最佳时机
题目:121. 买卖股票的最佳时机 - 力扣(LeetCode)
dp数组及下标含义
dp[i][0]为第i天持有股票获得的利润,dp[i][1]为第i天不持有股票获得的利润
递推公式
如果第i天持有股票:
第i - 1天已持有股票,dp[i][0] = dp[i - 1][0]
第i天买入股票,dp[i][0] = -prices[i]
dp[i][0] = max(dp[i - 1][0], -prices[i])
如果第i天不持有股票:
第i - 1天不持有股票,dp[i][1] = dp[i - 1][1]
第i天卖出持有股票,dp[i][1] = dp[i - 1][0] + prices[i]
dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] + prices[i])
初始化
由递推公式可知,dp[0][0]和dp[0][1]需要初始化
dp[0][0] = -prices[0]
dp[0][1] = 0
遍历顺序
从小到大遍历
int maxProfit(vector<int>& prices) {
if(prices.size() == 0)
return 0;
vector<vector<int>> dp(prices.size(), vector<int>(2, 0));
dp[0][0] = -prices[0];
for(int i = 1; i < prices.size(); i++){
dp[i][0] = max(dp[i - 1][0], -prices[i]);
dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] + prices[i]);
}
return dp[prices.size() - 1][1];
}
买卖股票的最佳时机2
题目:122. 买卖股票的最佳时机 II - 力扣(LeetCode)
dp数组及下标含义
dp[i][0]为第i天持有股票的利润,dp[i][1]为第i天不持有股票的利润
递推公式
如果第i天持有股票:
第i - 1天持有股票,dp[i][0] = dp[i - 1][0]
第i天买入股票,dp[i][0] = dp[i - 1][1] - prices[i]
dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] - prices[i])
如果第i天不持有股票:
第i - 1天不持有股票,dp[i][1] = dp[i - 1][1]
第i天卖出股票,dp[i][1] = dp[i - 1][0] + prices[i]
dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] + prices[i])
初始化
dp[0][0] = -prices[0]
dp[0][1] = 0
遍历顺序
从小到大遍历
int maxProfit(vector<int>& prices) {
if(prices.size() == 0)
return 0;
vector<vector<int>> dp(prices.size(), vector<int>(2, 0));
dp[0][0] = -prices[0];
for(int i = 1; i < prices.size(); 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 - 1][0] + prices[i]);
}
return dp[prices.size() - 1][1];
}
买卖股票的最佳时机3
题目:123. 买卖股票的最佳时机 III - 力扣(LeetCode)
dp数组及下标含义
dp[i][0]表示第一次持有股票的利润
dp[i][1]表示第一次未持有股票的利润
dp[i][2]表示第二次持有股票的利润
dp[i][3]表示第二次未持有股票的利润
递推公式
dp[i][0] = max(dp[i - 1][0], -prices[i])
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[0][0] = -prices[0]
dp[0][1] = 0
dp[0][2] = -prices[0]
dp[0][3] = 0
遍历顺序
从小到大遍历
int maxProfit(vector<int>& prices) {
if(prices.size() == 0)
return 0;
vector<vector<int>> dp(prices.size(), vector<int>(4, 0));
dp[0][0] = -prices[0];
dp[0][2] = -prices[0];
for(int i = 1; i < prices.size(); i++){
dp[i][0] = max(dp[i - 1][0], -prices[i]);
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]);
}
return dp[prices.size() - 1][3];
}
买卖股票的最佳时机4
题目:188. 买卖股票的最佳时机 IV - 力扣(LeetCode)
dp数组及下标含义
dp[i][2k - 1]表示第k次持有股票,dp[i][2k]表示第k次未持有股票
递推公式
dp[i][2k - 1] = max(dp[i - 1][2k - 1], dp[i - 1][2k - 2] - prices[i])
dp[i][2k] = max(dp[i - 1][2k], dp[i][2k - 1] + prices[i])
初始化
dp[0][2k - 1] = -prices[0], dp[0][2k] = 0
遍历顺序
从小到大遍历
int maxProfit(int k, vector<int>& prices) {
vector<vector<int>> dp(prices.size(), vector<int>(2 * k + 1, 0));
for(int j = 1; j <= k; j++)
dp[0][2 * j - 1] = -prices[0];
for(int i = 1; i < prices.size(); i++){
for(int j = 1; j <= k; j++){
dp[i][2 * j - 1] = max(dp[i - 1][2 * j - 1], dp[i - 1][2 * j - 2] - prices[i]);
dp[i][2 * j] = max(dp[i - 1][2 * j], dp[i][2 * j - 1] + prices[i]);
}
}
return dp[prices.size() - 1][2 * k];
}
最佳买卖股票时机含冷冻期
题目:Loading Question... - 力扣(LeetCode)
dp数组及下标含义
]dp[i][j]表示第i天达到状态j获得的利润
j = 0:持有股票
j = 1:至少两天前卖出股票,已度过冷冻期
j = 2:今天卖出股票,明天进入冷冻期
j = 3:昨天卖出股票,今天是冷冻期
注意:未持有股票的状态需要划分为两种,因为冷冻期的来源只限前一天卖出的,即j = 2,而未持有股票状态包括j = 1和j = 2
递推公式
持有股票的来源有:前一天持有股票,前一天j = 1时买入股票,前一天j = 3时买入股票
dp[i][0] = max(dp[i - 1][0], max(dp[i - 1][1], dp[i - 1][3]) - prices[i])
j = 1时,来源有:前一天状态j = 1,前一天是冷冻期
dp[i][1] = max(dp[i - 1][1], dp[i - 1][3])
j = 2,卖出股票,利润增加
dp[i][2] = dp[i - 1][0] + prices[i]
j = 3,今天是冷冻期,利润应与前一天卖出股票的利润相同
dp[i][3] = dp[i - 1][2]
初始化
dp[0][0] = -prices[i]
dp[0][1] = dp[0][2] = dp[0][3] = 0
遍历顺序
从小到大
int maxProfit(vector<int> prices){
vector<vector<int>> dp(prices.size(), vector<int>(4, 0));
dp[0][0] = -prices[0];
for(int i = 1; i < prices.size(); i++){
dp[i][0] = max(dp[i - 1][0], max(dp[i - 1][1], dp[i - 1][3]) - prices[i]);
dp[i][1] = max(dp[i - 1][1], dp[i - 1][3]);
dp[i][2] = dp[i - 1][0] + prices[i];
dp[i][3] = dp[i - 1][2];
}
return max(dp[prices.size() - 1][1], max(dp[prices.size() - 1][2], dp[prices.size() - 1][3]));
}
买卖股票的最佳时机含手续费
题目:714. 买卖股票的最佳时机含手续费 - 力扣(LeetCode)
思路:这道题比较简单,就是在未持有股票状态的递推公式稍作修改即可,这里不再详述。
dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] + prices[i] - fee)
总结
解决股票问题的关键就是找准股票有哪几种状态,每种状态的来源是什么,并反映到dp数组上。