一、买卖股票的最佳时机含冷冻期
五部曲
- 确定dp数组,
dp[i][j],第i天状态为j,最多现金,有四种状态- 状态1,持有股票,今天买入,或者之前就买入,现在持有
- 不持有股票
- 状态2,保持卖出股票的状态,两天前卖出股票,度过了一天冷冻期,一天前卖出股票,没有操作
- 状态3,今天卖出股票 这里单独设置状态是因为,状态4的前一天一定是卖出股票
- 状态4,今天是冷冻期,只有一天
- 确定递推公式
- 状态1,持有股票
- 今天买入
- 前一天是保持卖出股票的状态,
dp[i-1][1] - prices[i] - 前一天是冷冻期,
dp[i-1][3] - prices[i] Math.max(dp[i-1][1] - prices[i], dp[i-1][3] - prices[i])
- 前一天是保持卖出股票的状态,
- 前一天就是持有股票,
dp[i-1][0] dp[i][0] = Math.max(Math.max(dp[i-1][1] - prices[i], dp[i-1][3] - prices[i]), dp[i-1][0])
- 今天买入
- 状态2,保持不持有股票
- 前一天冷冻期,
dp[i-1][3] - 前一天就是卖出的状态,
dp[i-1][1] dp[i][1] = Math.max(dp[i-1][3], dp[i-1][1])
- 前一天冷冻期,
- 状态3,今天卖出股票,昨天一定是持有股票,
dp[i][2] = dp[i-1][0] + prices[i] - 状态4,今天冷冻期,昨天一定卖出了股票,
dp[i][3] = dp[i-1][2]
- 状态1,持有股票
- dp数组初始化
- 状态1,
dp[0][0] = -prices[0] - 状态2和状态3和状态4,
dp[0][1] = 0; dp[0][2] = 0;dp[0][3] = 0
- 状态1,
- 遍历顺序从前往后
- 举例推导
最后结果取状态2,状态3,状态4,的最大值
时间复杂度:O(n) 空间复杂度:O(n)
/**
* @param {number[]} prices
* @return {number}
*/
var maxProfit = function(prices) {
let dp = new Array(prices.length).fill(0).map(_ => new Array(4).fill(0))
dp[0][0] = -prices[0]
for(let i = 1;i < prices.length;i++) {
dp[i][0] = dp[i][0] = Math.max(Math.max(dp[i-1][1] - prices[i], dp[i-1][3] - prices[i]), dp[i-1][0])
dp[i][1] = Math.max(dp[i-1][3], dp[i-1][1])
dp[i][2] = dp[i-1][0] + prices[i]
dp[i][3] = dp[i-1][2]
}
return Math.max(dp[prices.length - 1][1], dp[prices.length - 1][2], dp[prices.length - 1][3])
};
二、买卖股票的最佳时机含手续费
可以多次交易,每次交易都有手续费
主要区别在于递推公式
- 第i天持有股票
- 第i天保持持有,
dp[i - 1][0] - 第i天买入股票,
dp[i-1][1] - prices[i] dp[i][0] = Math.max(dp[i - 1][0], dp[i-1][1] - prices[i])
- 第i天保持持有,
- 第i天不持有股票
- 第i天保持不持有,
dp[i-1][1] - 第i天卖出,
dp[i-1][0]+ prices[i] -free dp[i][1] = Math.max(dp[i-1][1], dp[i-1][0]+ prices[i] -fee)
- 第i天保持不持有,
卖出的时候计算手续费
/**
* @param {number[]} prices
* @param {number} fee
* @return {number}
*/
var maxProfit = function(prices, fee) {
let dp = new Array(prices.length).fill(0).map(_ => [0, 0])
dp[0][0] = -prices[0]
for(let i = 1; i < prices.length;i++) {
dp[i][0] = Math.max(dp[i - 1][0], dp[i-1][1] - prices[i])
dp[i][1] = Math.max(dp[i-1][1], dp[i-1][0]+ prices[i] -fee)
}
return dp[prices.length-1][1]
};
买入的时候计算手续费
/**
* @param {number[]} prices
* @param {number} fee
* @return {number}
*/
var maxProfit = function(prices, fee) {
let dp = new Array(prices.length).fill(0).map(_ => [0, 0])
dp[0][0] = -prices[0] - fee
for(let i = 1; i < prices.length;i++) {
dp[i][0] = Math.max(dp[i - 1][0], dp[i-1][1] - prices[i] - fee)
dp[i][1] = Math.max(dp[i-1][1], dp[i-1][0]+ prices[i])
}
return dp[prices.length-1][1]
};