代码随想录算法训练营第四十八天 | 121. 买卖股票的最佳时机、122. 买卖股票的最佳时机 II

36 阅读1分钟

121. 买卖股票的最佳时机

链接

文章链接

题目链接

第一想法

说来惭愧,这次的想法感觉是动态规划,但是不会用动态规划写,所以尝试了用了算是动态规划的变种,核心思想为每次遍历就找到当前遍历过的最小值,之后用当前价格减去最小价格,然后求得哪个利润最大就可以,代码如下:

function maxProfit(prices: number[]): number {
  let max: number = 0//记录利润最大值
  let min: number = prices[0]//记录最小价格
  for (let i = 0; i < prices.length; i++) {
    min = Math.min(prices[i], min)//找到遍历过的最小价值
    max = Math.max(prices[i] - min, max)//找到利润最大值
  }
  return max
}

看完文章后的想法

寄,其实我的想法就是贪心算法,动态规划根本不是我上面考虑的那样,说实话,确实没想到,刚刚没看文章的时候就像想过是不是二维数组,但是没深想。但是看完文章后发现就是二维数组,大意了.....接下来递归五部曲:

  1. 首先是dp数组这是一个二维数组dp[i]表示第i天的状态,其中dp[i][0]是当天持有股票的最大现金数,dp[i][1]是当天没有持有股票的最大现金数,注意持有不一定是买入,例如第一天买入,第三天卖出,则第一第二天都是持有状态
  2. 初始化,这个初始化要根据递推公式来这里先写为dp[0]=[-prices[0],0]
  3. 递推公式分为两个:首先是dp[i][0],如果第i天持有,则有两种情况,第一种为i-1天也持有,就是dp[i-1][0],第二种情况就是第i天买股票(持有),就是为-prices[i],所以dp[i][0] = Math.max(dp[i - 1][0], -prices[i]);之后就是dp[i][1]的情况,也分为两种,第i-1天也没持有,那么就是dp[i][1],第二种情况是i-1天持有而第i天没持有(就是第i天买了),所以获得的金额为 prices[i] + dp[i - 1][0](当天卖出+之前有的金额),所以递推公式为dp[i][1] = Math.max(dp[i - 1][1], prices[i] + dp[i - 1][0]),因为第i天的状态和i-1天相同,所以要初始化dp[0],也就是我上面所写的,不明白可以看代码随想录的视频讲解
  4. 遍历顺序,很简单,从左往右
  5. 举例:

image.png 代码如下:

function maxProfit(prices: number[]): number {
  let dp: number[][] = new Array(prices.length).fill(0).map((item) => new Array())//dp二维数组
  dp[0] = [-prices[0], 0]//初始化
  for (let i = 1; i < prices.length; i++) {
    dp[i][0] = Math.max(dp[i - 1][0], -prices[i])//第i天持有股票的最大值
    dp[i][1] = Math.max(dp[i - 1][1], prices[i] + dp[i - 1][0])//第i天不持有股票的最大值
  }
  return dp[prices.length - 1][1]//这里返回不持有股票得到现金数,因为不持有股票的现金数一定大于持有股票的陷阱数
}

思考

这道题我写出来贪心算法,但是动态规划的写法确实没想出来,得继续加油了。

122. 买卖股票的最佳时机 II

链接

文章链接

题目链接

第一想法

这道题之前是拿贪心算法写的,这次按照刚刚学的动态规划写一遍,因为刚刚看了买卖股票的最佳时机I的视频讲解,所以对这个可以多次购买有了一定的了解,接下来就是递归五部曲

  1. dp数组的含义还是一样的dp[i][0]表示持有股票时现金的最大值,dp[i][1]表示不持有股票时现金的最大值
  2. 递推公式:首先是dp[i][0],dp[i][0]有两种情况,第一种是i-1天就持有,所以现金数为dp[i-1][0],第二种是在第i天进行购买,因为一次最多只能持有一只股票,所以现金的最大值为dp[i-1][1]-prices[i](第i-1天没有持有股票加上第i天持有股票)
  3. 初始化,按照递推公式的含义,所以还是dp[0]=[-prices[0],0]
  4. 遍历顺序,因为要用到i-1天,所以还是从前到后

代码如下

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 - 1][1] - prices[i])//与买卖股票的最佳时机I的唯一差别之处
    dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] + prices[i])
  }
  return dp[prices.length - 1][1]
}

看完文章后的想法

整体思路是和文章一样的,所以这里就不再赘述了。如果还是不理解可以去看代码随想录的文章。

思考

这道题因为之前看过121. 买卖股票的最佳时机的视频讲解,所以对dp数组的含义有了深刻的了解,这道题就很快的写出来了。

今日总结

今天总共就两道题,整体不算太难,但是确实是自己能力不够,没有完全写出来,第一次遇到买卖股票的最佳时机用动态规划的写法,所以对dp数组什么含义都不太理解,但是看完视频讲解后就了解很多了。今日耗时2.5小时