一、买卖股票的最佳时机3
相比于上两题,最多可以买卖两次,可能性为,买卖0次,1次,2次
五部曲
- dp数组的下标以及含义,
- 一共有5种状态, 不一定非得第i天买入,而是持有状态, 不一定非得第i天卖出,而是不持有状态
0. 没有操作
- 第一次持有股票,
- 第一次不持有股票
- 第二次持有股票
- 第二次不持有股票
dp[i][j], 表示第i天状态j所剩下的最大现金
- 一共有5种状态, 不一定非得第i天买入,而是持有状态, 不一定非得第i天卖出,而是不持有状态
0. 没有操作
- 确定递推公式,
- 确定
dp[i][1],第i天,第一次持有股票- 第i天第一次买入,
dp[i][1] = dp[i-1][0] - price[i] - 第i天没有操作,
dp[i][1] = dp[i-1][1] dp[i][1] = Math.max(dp[i-1][0] - price[i], dp[i-1][1])
- 第i天第一次买入,
- 确定
dp[i][2], 第i天,第一次不持有股票- 第i天第一次卖出,
dp[i][2] = dp[i-1][1] + price[i] - 第i天没有操作,
dp[i][2] = dp[i-1][2] dp[i][2] = Math.max(dp[i-1][1] + price[i], dp[i-1][2])
- 第i天第一次卖出,
- 确定
dp[i][3],第i天,第二次持有股票- 第i天第二次买入,
dp[i][3] = dp[i-1][2] - price[i] - 第i天没有操作,
dp[i][3] = dp[i-1][3] dp[i][3] = Math.max(dp[i-1][2] - price[i], dp[i-1][3])
- 第i天第二次买入,
- 确定
dp[i][4], 第i天,第二次不持有股票- 第i天第二次卖出,
dp[i][4] = dp[i-1][3] + price[i] - 第i天没有操作,
dp[i][4] = dp[i-1][4] dp[i][4] = Math.max(dp[i-1][3] + price[i], dp[i-1][4])
- 第i天第二次卖出,
- 确定
- dp数组初始化
dp[0][0] = 0dp[0][1]= -prices[0],第一次买入dp[0][2]= 0dp[0][3]= -prices[0]dp[0][4]= 0
- 确定遍历顺序,从前到后
- 举例推导
最大的情况一定是卖出的状态,两次卖出一定是最后一次卖出最大,因为最后一次卖出包含了第一次卖出,当天买,当天卖
/**
* @param {number[]} prices
* @return {number}
*/
var maxProfit = function(prices) {
let dp = new Array(prices.length).fill(0).map(_ => new Array(5).fill(0))
dp[0][1] = -prices[0]
dp[0][3] = -prices[0]
for(let i = 1; i < prices.length;i++) {
dp[i][1] = Math.max(dp[i-1][0] - prices[i], dp[i-1][1])
dp[i][2] = Math.max(dp[i-1][1] + prices[i], dp[i-1][2])
dp[i][3] = Math.max(dp[i-1][2] - prices[i], dp[i-1][3])
dp[i][4] = Math.max(dp[i-1][3] + prices[i], dp[i-1][4])
}
return dp[prices.length-1][4]
};s
时间复杂度:O(n) 空间复杂度:O(n × 5)
二、买卖股票的最佳时机4
和上题相比,这里最多有k笔交易
五部曲
dp[i][j], 表示第i天状态j所剩下的最大现金,除了0天,偶数天表示不持有股票,奇数天表示持有股票,j的范围定义为2 * k + 1即可- 递推公式
for(let j = 0; j < 2 * k - 1;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])
}
- 初始化,
for(let j = 1; j < 2 * k; j+=2) {
dp[0][j] = -prices[0]
}
- 遍历顺序
- 推导
时间复杂度: O(n * k),其中 n 为 prices 的长度 空间复杂度: O(n * k)
/**
* @param {number} k
* @param {number[]} prices
* @return {number}
*/
var maxProfit = function (k, prices) {
let dp = new Array(prices.length).fill(0).map(_ => new Array(2 * k + 1).fill(0))
for (let j = 1; j < 2 * k; j += 2) {
dp[0][j] = -prices[0]
}
console.log(dp)
for (let i = 1; i < prices.length; i++) {
for (let j = 0; j < 2 * k - 1; 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]
};