力扣123.买卖股票的最佳时机3
题目链接:https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-iii/
思路
本题可以买卖两次,比买卖股票的最佳时机要多出几个状态。
dp数组的含义:
(1)dp[i][0]:第i天不操作的最大金额
(2)dp[i][1]:第i天第一次持有的最大金额
(3)dp[i][2]:第i天第一次不持有的最大金额
(4)dp[i][3]:第i天第二次持有的最大金额
(5)dp[i][4]:第i天第二次不持有的最大金额
递推公式:
(1)第i天不操作的情况只能由第i-1天不操作延续,实际上这个可以不写
(2)第i天第一次持有的最大金额可以由:1.前一天已经第一次持有;2.前一天未持有,在这天进行买入
(3)第i天第一次不持有的最大金额可以由:1.前一天已经第一次不持有;2.前一天持有,在这天进行卖出
(4)第i天第二次持有的最大金额可以由:1.前一天已经第二次持有;2.前一天未持有,在这天进行买入
(5)第i天第二次不持有的最大金额可以由:1.前一天已经第二次不持有;2.前一天持有,在这天进行卖出
初始化:
(1)dp[0][0]:不操作其实就是0
(2)dp[0][1]:第0天想要持有,只能进行买入
(3)dp[0][2]:第0天卖出,收益为0
(4)dp[0][3]:第0天第二次买入
(5)dp[0][4]:第0天第二次卖出,收益还是为0
遍历顺序
同买卖股票1
打印数组
最大金额肯定是第二次不持有,即dp[prices.length-1][4]
完整代码
class Solution {
public int maxProfit(int[] prices) {
int[][] dp = new int[prices.length][5];
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.length; i++) {
dp[i][0] = dp[i-1][0];
dp[i][1] = Math.max(dp[i-1][1],-prices[i]);
dp[i][2] = Math.max(dp[i-1][2],dp[i-1][1]+prices[i]);
dp[i][3] = Math.max(dp[i-1][3],dp[i-1][2]-prices[i]);
dp[i][4] = Math.max(dp[i-1][4],dp[i-1][3]+prices[i]);
}
return dp[prices.length-1][4];
}
}
力扣188.买卖股票的最佳时机4
题目链接:https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-iv/
思路
买卖2次需要4个状态来表示,那么买卖k次需要2k个状态来表示,加上dp[i][0]这个不操作的初始状态,需要2k+1个状态。
我们采用j来控制每次买卖的递推,j+1代表持有股票,j+2代表不持有股票,j每次跳跃2,就能表示所有的买卖状态。
初始化:观察可以得到,第0天时,当j为奇数时,是买入状态,金额是-prices[0];否则为0.
完整代码
class Solution {
public int maxProfit(int k, int[] prices) {
int[][] dp = new int[prices.length][2*k+1];
for (int j = 1; j < 2*k; j+=2) {
dp[0][j] = -prices[0];
}
for (int i = 1; i < prices.length; i++) {
for (int j = 0; j < 2*k; j+=2) {
dp[i][j+1] = Math.max(dp[i-1][j+1],dp[i-1][j]-prices[i]);
dp[i][j+2] = Math.max(dp[i-1][j+2],dp[i-1][j+1]+prices[i]);
}
}
return dp[prices.length-1][2*k];
}
}