LeetCode每日一题之买卖股票的最佳时机含手续费

141 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第4天,点击查看活动详情

题目介绍

30a0c19ebe92d187449ac82ac7235ac.jpg

题目分析

该题相比于买卖股票的最佳时机含冷冻期比较简单,没有冷冻期,所以只需要区分买入状态和卖出状态即可,唯一不同的是买入卖出时需要支付一次手续(注意:不是买入、卖出都需要支付手续费,一次完整交易只需要支付一次手续费即可)。

状态转移分析

dp[i][j] 表示第i天第j种状态所拥有的最大收益值,其中j有两种状态:  
0: 买入状态,可能是今天买入,也可能是之前某一天买入
1:卖出状态,可能是今天卖出,也可能是之前某一天卖出
dp[i][0]: dp[i-1][0]  dp[i-1][1] - prices[i] 取二者最大值
dp[i][1]dp[i-1][1]  dp[i-1][0] + prices[i] - fee  当天卖出要收手续费,取二者最大值
初始化: dp[0][0] = -prices[i] 第一天买入  dp[0][1] = -fee 买入卖出 收手续费
dp[i]dp[i-1]推导出来,所以应该从前往后遍历
最终收益最大值一定是卖出状态,dp[prices.length-1][1]

代码实现

var maxProfit = function(prices, fee) {
   /**
     dp[i][j] 表示第i天j种状态的收益最大值
     j = 0 ;买入状态  
     j = 1 卖出状态

     dp[i][0] = dp[i-1][0] dp[i-1][1] - prices[i]
     dp[i][1] = dp[i-1][1]  dp[i-1] + prices[i] - 2


     dp[0][0] = -prices[0]
     dp[0][1] = 0
    */

    const dp = Array.from(Array(prices.length),() => Array(2).fill(0))
    dp[0][0] = -prices[0]
    dp[0][1] = 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]
};

贪心算法

其实本题也可采用贪心算法实现,每次都在最低点买入,最高点卖出(减去手续费),如果收益值为正则卖出,累计计算每次收益的和,计算利润时,可能有多次计算利润,最后一次计算利润才是真正意义的卖出

var maxProfit = function(prices, fee) {
  let minPrice = prices[0]
  let result = 0
  for(let i = 1;i<prices.length;i++){
      if(prices[i]<minPrice){
          minPrice = prices[i] // 每次更新最小值
      }

      if(prices[i]>minPrice&&prices[i]-minPrice<=fee){
          continue; // 收益小于手续费不操作
      }

      if(prices[i] - minPrice > fee){
          result += prices[i] - minPrice - fee; //收益值为正则卖出
          minPrice = prices[i] - fee;  // 每次计算收益并不是真正的卖出,可能是持有,只有真正卖出才计算手续费, 减去fee避免重读计算手续费
      }
  }

  return result;
};