代码随想录算法训练营第五十一天 | 309. 最佳买卖股票时机含冷冻期、714. 买卖股票的最佳时机含手续费

38 阅读2分钟

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

链接

文章链接

题目链接

第一想法

之前做过买卖股票的最佳时机I、II、III、IV,所以这道题只是添加了一个冷冻期,昨天卖了今天不能买,只能第二天再买,所以就是把递推公式改一下就可以了,接下来递归五部曲:

  1. dp数组的含义,还是和I是一样的,dp[i][0]是持有股票时现金的最大值,dp[i][1]是不持有股票时现金的最大值
  2. 递推公式:dp[i][1]还是一样的,有两种情况,第i-1天就是不持有和第i-1天持有而第i天卖出,所以递推公式为 dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] + prices[i]);唯一不同的就是dp[i][0]了,也是有两种情况,第一种是第i-1天就持有,第二种是i-1天不持有,第i天想买,如果想买的话,因为有冷冻期,所以最起码在i-2天就不持有股票时第i天才能买,所以递推公式为 dp[i][0] = Math.max(dp[i - 1][0], (dp[i - 2]?.[1] || 0) - prices[i])这里的?.是js的语法,前面为undefined时就返回0
  3. 初始化,还是一样的dp[0] = [-prices[0], 0]
  4. 遍历顺序也是一样的

代码如下:

function maxProfit(prices: number[]): number {
  let dp: number[][] = new Array(prices.length).fill(0).map((item) => new Array())
  dp[0] = [-prices[0], 0]
  for (let i = 1; i < prices.length; i++) {
    dp[i][0] = Math.max(dp[i - 1][0], (dp[i - 2]?.[1] || 0) - prices[i])
    dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] + prices[i])
  }
  return dp[prices.length - 1][1]
}

看完文章后的想法

文章的想法是和我的完全不一样的,但是我感觉我的思路也是正确的,文章也是用的二维数组,但是它的dp[i]有四个状态,分别为dp[i][0]:持股状态,dp[i][1]:不持股但是也不是冷冻期,dp[i][2]:不持股但是是今天卖出,dp[i][3]:不持股今天是冷冻期。那么直接递归五部曲:

  1. dp数组的含义,上面已经说了,所以这里不再多说了、
  2. 递推公式,首先是dp[i][0],共有三种情况,第i-1天就是持有状态,第二种是当前购买且前一天是不持股状态也不是冷冻期,第三种情况是当天购买且前一天是冷冻期;dp[i][1]有两种状态,第一种是i-1天是不持股状态也不是冷冻期,第二种是i-1天是冷冻期;dp[i][2],当前卖出只有状态,只有i-1天是持有状态,dp[i][3]也只有一种状态,i-1天是卖出股票的状态
  3. 初始化,很容易理解,除了持有股票,其他都是0
  4. 遍历顺序还是一样的
function maxProfit(prices: number[]): number {
  let dp: number[][] = new Array(prices.length).fill(0).map((item) => new Array())
  dp[0] = [-prices[0], 0, 0, 0]
  for (let i = 1; i < prices.length; 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[prices.length - 1][1], dp[prices.length - 1][2], dp[prices.length - 1][3])
}

思考

这道题不是很难,但是我和文章的思路是不太相同的,文章把状态分的很细,但是由于是自己想的,还是认为自己的比较好理解。

714. 买卖股票的最佳时机含手续费

链接

题目链接

文章链接

第一想法

之前是拿贪心算法写的,不太好理解,这次拿动态规划写,由于之前写了很多的买卖股票的题,所以这回非常就想到了,只要在卖股票的时候再减一个手续费就可以了,递归五部曲

  1. dp数组的含义,dp[i][0]是持有股票时的最大现金数,dp[i][1]是不持有股票时的最大现金数
  2. 递推公式,dp[i][0]还是不变的,有两种情况,前一天就持有或者是前一天不持有今天购买dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] - prices[i])dp[i][1]也是两种情况,前一天就不持有或者是前一天持有今天选择卖出,那么卖出则需要支付手续费dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] + prices[i] - fee)
  3. 初始化,还是dp[0]=[-prices[i],0]
  4. 遍历顺序还是从前往后的
function maxProfit(prices: number[], fee: number): number {
  let dp: number[][] = new Array(prices.length).fill(0).map((item) => new Array())
  dp[0] = [-prices[0], 0]
  for (let i = 1; i < prices.length; i++) {
    dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] - prices[i])
    dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] + prices[i] - fee)
  }
  return dp[prices.length - 1][1]
}

看完文章后的想法

文章的想法和我的想法是一样的,所以这里就不多赘述了

思考

这道题不算太难,只要把卖股票的时候添加上手续费就可以了

今日总结

今天都不算太难,主要是利用买卖股票的模版加上变一下递推公式就可以了,所以没费很长时间,今日耗时2小时