「算法」714. 买卖股票的最佳时机含手续费 | 刷题打卡

371 阅读2分钟

一、题目描述:

给定一个整数数组 prices,其中第 i 个元素代表了第i 天的股票价格 ;非负整数 fee 代表了交易股票的手续费用。

你可以无限次地完成交易,但是你每笔交易都需要付手续费。如果你已经购买了一个股票,在卖出它之前你就不能再继续购买股票了。

返回获得利润的最大值。

注意: 这里的一笔交易指买入持有并卖出股票的整个过程,每笔交易你只需要为支付一次手续费。

原题链接 👉 714. 买卖股票的最佳时机含手续费

示例 1:

输入: prices = [1, 3, 2, 8, 4, 9], fee = 2
输出: 8
解释: 能够达到的最大利润:  
在此处买入 prices[0] = 1
在此处卖出 prices[3] = 8
在此处买入 prices[4] = 4
在此处卖出 prices[5] = 9
总利润: ((8 - 1) - 2) + ((9 - 4) - 2) = 8.

注意:

  • 0 < prices.length <= 50000.
  • 0 < prices[i] < 50000.
  • 0 <= fee < 50000.

二、思路分析:

思路1:动态规划

  1. 最后一天,只有2种状态:手上无股票,手上有股票

  2. 对应最大利润dp = [无股票最大利润,有股票最大利润]

  3. 初始条件:dp[0][0] = 0, dp[1][0]=- 第0日股票价格

  4. 第1日开始,状态转移方程

    dp[i][0]=max(dp*[i−1][0],* dp*[i−1][1]+prices[i]−*fee)

    dp[i][1]=max(dp[i−1][1],dp[i−1][0]−prices[i])

  5. 由于全部交易结束后,持有股票的收益一定低于不持有股票的收益,因此这时候 dp[n-1][0] 的收益必然是大于 dp[n-1][1] 的,最后的答案即为 dp[n-1][0]。

代码

var maxProfit = function (prices, fee) {
  const n = prices.length
  let dp = new Array(prices.length).fill(0).map((v) => new Array(2).fill(0))
  dp[0][0] = 0
  dp[0][1] = -prices[0]
  for (let i = 1; i < prices.length; i++) {
    dp[i][0] = Math.max(dp[i - 1][1] + prices[i] - fee, dp[i - 1][0])
    dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] - prices[i])
  }
  return dp[n - 1][0]
}

复杂度分析

  • 时间复杂度:O(n),其中 n 为数组的长度。一共有 2n 个状态,每次状态转移的时间复杂度为 O(1),因此时间复杂度为 O(2n)=O(n)。

  • 空间复杂度:O(n) 或 O(1),取决于是否使用数组存储所有的状态。

思路2:贪心算法

  1. 我们用buy来记录手上拥有的股票的最低买入价格,用money来记录股票的整体收益。
  2. 遍历数组prices,当price[i]+fee < buy时,将buy更新为price[i]+fee,这样才能保证我们以更低的价格购买。
  3. 当前股票价格price[i]>buy时卖出股票,同时把buy价格调整为price[i]。因为我们不知道当前价格是否是最高的,所以可以有一个反悔操作。如果下一天价格更高,下一天的收益为price[i+1]-price[i]当我们卖出一支股票时,我们就立即获得了以相同价格并且免除手续费买入一支股票的权利
  4. 在遍历完整个数组 prices 之后之后,我们就得到了最大的总收益。

代码

var maxProfit = function (prices, fee) {
  let buy = prices[0] + fee
  let money = 0
  for (let i = 1; i < prices.length; i++) {
    if (prices[i] > buy) {
      money += prices[i] - buy
      buy = prices[i]
    } else if (prices[i] + fee < buy) {
      buy = prices[i] + fee
    }
  }
  return money
}

复杂度分析

  • 时间复杂度:O*(*n),n为数组的长度。
  • 空间复杂度:O(1),只使用了常数个变量。

三、总结:

  • 本题和 122. 买卖股票的最佳时机 II 是非常类似的题,唯一的区别就在于本题有「手续费」而第 122 题没有。

  • 本题可以使用动态规划来解,注意推算动态规划的状态转移方程

    dp[i][0]=max(dp*[i−1][0],* dp*[i−1][1]+prices[i]−*fee)

    dp[i][1]=max(dp[i−1][1],dp[i−1][0]−prices[i])

  • 本题还可以用贪心算法来解

——

本文正在参与「掘金 2021 春招闯关活动」, 点击查看 活动详情