携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第3天,点击查看活动详情
题目分析
该题与之前的买卖股票的最佳时机III有一定的区别,前一题最多可以买卖两次,该题不限制买卖次数,但是有一个冷冻期,所以在转换上有一定的区别,我们还是从状态开始分析,官方题解上分了三个状态,老实说我没怎么看明白,这里再次推荐一下代码随想录 ,其中分了四个状态,下面是我看完后的理解:
状态1: 买入状态, 可能是今天买入,也可能是之前某一天买入之后就没有卖出
状态2: 保持卖出状态, 可能前一天是冷冻期,也可能是前一天就是保持卖出状态
状态3: 今天卖出状态, 在今天刚好卖出
状态4: 冷冻期, 前一天卖出
状态转移公式定义:
dp[i][j] 表示第i天第j种状态所拥有的最大收益
dp[i][0] 前一天就是买入状态 dp[i-1][0], 前一天是保持卖出状态 dp[i-1][1] -prices[i],
前一天是冷冻期,dp[i-1][3] - prices[i] 求最大收益,所以取三者最大值
dp[i][1] 1.今天保持不便 dp[i-1][1] 2.前一天是冷冻期 dp[i-1][3]
dp[i][2] 前一天只能是买入状态 ,dp[i-1][0] + prices[i]
dp[i][3] 前一天只能是今天卖出状态 dp[i-1][2]
初始值定义:
dp[0][0] = -prices[0] dp[0][1] = 0 dp[0][2]=0 dp[0][3]=0
由状态转移公式可知遍历顺序为从前往后,最后最大收益值可能为保持卖出状态、今天卖出、冷冻期状态,取最大值
代码实现
以下为Javascript代码实现
/**
* @param {number[]} prices
* @return {number}
*/
var maxProfit = function(prices) {
const len = prices.length;
// const dp = new Array(len).fill(new Array(4).fill(0)) 这里有fill一个巨坑,之前从没注意过
const dp = Array.from(Array(len),() => Array(4).fill(0))
dp[0][0] = -prices[0]
for(let i = 1;i < len;i ++){
dp[i][0] = Math.max(dp[i-1][0],dp[i-1][1]-prices[i],dp[i-1][3]-prices[i])
dp[i][1] = Math.max(dp[i-1][1],dp[i-1][3])
dp[i][2] = dp[i-1][0] + prices[i]
dp[i][3] = dp[i-1][2]
}
return Math.max(dp[len-1][1],dp[len-1][2],dp[len-1][3])
};
血的教训
这里因为数组fill方法引发了一场血案 ,最开始写出代码后一直运行不通过,比对了状态转移公式,没有问题,老老实实的在vscode中打印了一下dp:
发现每一项的内容都是一样,查看官网才发现,数组fill方法如果填充的类型为对象,那么被赋值的是同一个内存地址的对象,而不是深拷贝对象。