最佳买卖股票时机含冷冻期

91 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第3天,点击查看活动详情 62E509A0-3F0D-4271-93C4-0F8220C65BA4.png

题目分析

该题与之前的买卖股票的最佳时机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:

E8F08465-70BE-4be8-8502-86A9AFD57490.png
发现每一项的内容都是一样,查看官网才发现,数组fill方法如果填充的类型为对象,那么被赋值的是同一个内存地址的对象,而不是深拷贝对象。