本文已参与「新人创作礼」活动,一起开启掘金创作之路。
大家好,我依旧是人不狠话也不多的我,直接进入正题,希望看过的人都会做
题意: 给定一个数组,它的第 i 个元素是一支给定的股票在第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你最多可以完成 两笔 交易。
注意: 你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
来源:力扣(LeetCode) 链接: leetcode.cn/problems/be…
示例
输入: prices = [3,3,5,0,0,3,1,4]
输出: 6
解释: 在第 4 天(股票价格 = 0)的时候买入,在第 6 天(股票价格 = 3)的时候卖出,这笔交易所能获得利润 = 3-0 = 3 。 随后,在第 7 天(股票价格 = 1)的时候买入,在第 8 天 (股票价格 = 4)的时候卖出,这笔交易所能获得利润 = 4-1 = 3 。
算法思想:动态规划
与买卖股票的最佳时机I和与买卖股票的最佳时机II相比,解题思路虽然还是动态规划,但是这道题目难度提高了不少,
解:
首先我们要知道,在每一天,我们都有四种状态 ,状态 这两个字我用了加粗,特别说明是状态,不是动作
-
第一次买入股票,手上持有一只股票
-
第一次卖出股票,第一次交易完成
-
第二次买入股票,手上持有一只股票
-
第二次卖出股票,第二次交易完成
我们创建动态规划数组 dp[ i ] 表示每一天的收益,我们将每一天的状态 j( 0 < = j < 4 ) 添加 到 dp[ i ]
此时 dp[ i ][ j ] 表示第 i 天,第 j 个状态下的收益。
接着我们初始化 dp[ i ][ j ]
dp[0][0] = -prices[0] // 第一天,第一次买入股票,手上持有一只股票,此时收益为 -prices[0]
dp[0][1] = 0 // 第一天,第一次卖出股票,第一次交易完成,此时收益为 0 因为买入花了prices[0],卖出又赚了prices[0]
dp[0][2] = -prices[0] // 第一天,第二次买入股票,手上持有一只股票,此时收益又变为 -prices[0]
dp[0][3] = 0 // 第一天,第二次卖出股票,第二次交易完成,此时收益为 0
接着我们开始多维动态规划,每一种状态下我们都需要取最大值
// 第i天状态0情况下的最大收益:这种状态下有两种情况,一种是股票是昨天买的,一种是股票是今天买的,最大收益为两者更大值
// 股票如果是昨天买的,那么我们收益为dp[i-1][0],如果是今天买的,我们收益为减今天股票价格 -prices[i],
dp[i][0] = Math.max(dp[i - 1][0], -prices[i])
// 第i天状态1情况下的最大收益:这种状态有两种情况,一种是股票是昨天卖的,一种是股票是今天卖的,最大收益为两者更大值
// 如果股票是昨天卖的,那么我们收益为dp[i - 1][1],如果是今天卖的,我们就用昨天状态0的收益+今天股票价格prices[i]
dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] + 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])
总结
我们假设初始收益为0,买一次股票需要扣除当日股票的价格。 我们初始化了第一天的4中状态下的收益,从第二天开始循环,动态更新每一天,每种状态下的最大收益 最后我们返回,交易两次后的最大收益,因为中途我们一直在更新 dp 数组,所以交易两次后最大收益为第i天状态3情况下的值
代码
var maxProfit = function (prices) {
//创建dp数组
let dp = new Array(prices.length).fill(0).map(item => new Array(4).fill(0))
//对第一天状态做初始化
dp[0][0] = -prices[0]
dp[0][2] = -prices[0]
//循环,动态更新dp数组,详细规则参考上文
for (let i = 1; i < prices.length; i++) {
dp[i][0] = Math.max(dp[i - 1][0], -prices[i])
dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] + 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])
}
//返回我们需要的结果,最后一天的,买卖两次之后的最大收益
return dp[prices.length - 1][3]
};