携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第1天,点击查看活动详情
买卖股票的最佳时机III
题目描述
给定一个数组,它的第 i 个元素是一支给定的股票在第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你最多可以完成 两笔 交易。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
示例1:
输入:prices = [3,3,5,0,0,3,1,4]
输出:6
解释:在第 4 天(股票价格 = 0)的时候买入,在第 6 天(股票价格 = 3)的时候卖出,这笔交易所能获得利润 = 3-0 = 3 。
随后,在第 7 天(股票价格 = 1)的时候买入,在第 8 天 (股票价格 = 4)的时候卖出,这笔交易所能获得利润 = 4-1 = 3 。
示例2:
输入:prices = [1,2,3,4,5]
输出:4
解释:在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。
注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。
因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。
示例 3:
输入: prices = [7,6,4,3,1]
输出: 0
解释: 在这个情况下, 没有交易完成, 所以最大利润为 0。
示例 4:
输入: prices = [1]
输出: 0
写在前面
这道题目在leetcode上面归类为困难,一般遇到这种题目我是选择直接跳过,因为大部分困难类型的题目是联题解都看不明白的, 今天心血来潮看了下题解(代码随想录),居然看懂,下面根据题解来阐述一下我的理解。 根据题解应该用动态规划来解决,下面是动态规划步骤:
1.确定dp数组及下标含义:
/*
dp[i][j] 表示第i天的第j种状态收益最大值,根据题意可知j可以有五种状态 可用0-4表示,
其中: 0表示不变维持前一天的状态
1表示第一次买入操作
2表示第一次卖出操作
3表示第2次买入
4表示第二次卖出
dp[i][1] 表示的是第i天是第一次买入的状态,并不一定要是第i天买入的,有可能是之前某一天买入了,然后一直保持不变(开始不理解,后来写文章发现这句很重要)
*/
2.状态转移分析:
dp[i][0] 表示第i天不变,维持前一天状态,所以 dp[i][0] = dp[i-1][0]
dp[i][1] 表示第i天是第一次买入状态,可能是前一天就是第一次买入,今天不变,dp[i][1] = dp[i-1][1];也有可能前一天不持有,今天买入,dp[i][1] = dp[i-1][0] - prices[i] ,减去当天的股票值,取二者之间的最大值
dp[i][2] 表示第i天是第一次卖出状态, 可能前一天就是第一次卖出状态,dp[i][2] = dp[i-1][2];也有可能前一天是第一次持有状态,dp[i][2] = dp[i-1][1] + prices[i],取二者之间的最大值
dp[i][3] 表示第i天是第二次买入状态,同理可得:dp[i][3] = dp[i-1][3] || dp[i][3] = dp[i-1][2] - prices[i],取二者之间的最大值
dp[i][4] 表示第i天是第二次卖出状态,同理可得:dp[i][4] = dp[i-1][4] || dp[i][4] = dp[i-1][3] + prices[i],取二者之间最大值。
3.确定初始值:
dp[0][0] = 0; // 第一天不操作,收益为0
dp[0][1] = -prices[0]; // 第一天买入,收益为-prices[0]
dp[0][2] = 0; // 第一天买了又买了 收益为0
dp[0][3] = -prices[0] // 买-卖-买 收益为-prices[0]
dp[0][4] = 0 // 买-卖-买-卖 0
4.确定遍历顺序:
显而易见,应该从前往后遍历,由于每次都取最大值,二维数组的最后一个值, dp[prices.length-1][4] 就是最后的最大值
代码实现
// javascript实现
var maxProfit = function(prices) {
const len = prices.length;
const dp = new Array(len).fill(new Array(5))
dp[0][0] = 0;
dp[0][1] = -prices[0];
dp[0][2] = 0;
dp[0][3] = -prices[0];
dp[0][4] = 0;
for(let i = 1;i<len;i++){
dp[i][0] = dp[i-1][0];
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])
dp[i][4] = Math.max(dp[i-1][4],dp[i-1][3] + prices[i])
}
return dp[len-1][4]
}
这是我自己根据题解做的记录,算是一个里程吧,第一次看懂leetcode困难级别的题目,好多连题都读不懂。