714. 买卖股票的最佳时机含手续费(Best Time to Buy and Sell Stock with Transaction Fee)

3,907 阅读3分钟

"给血雨腥风的二级市场留下八个大字——巴菲特就那么回事"

题目链接: 714. 买卖股票的最佳时机含手续费,给定一个整数数组 prices,其中 prices[i] 表示第 i 天的股票价格 ;整数 fee 代表了交易股票的手续费用。你可以无限次地完成交易,但是你每笔交易都需要付手续费。如果你已经购买了一个股票,在卖出它之前你就不能再继续购买股票了。返回获得利润的最大值。注意:这里的一笔交易指买入持有并卖出股票的整个过程,每笔交易你只需要为支付一次手续费。

输入prices=[1,3,2,8,4,9],fee=2prices = [1, 3, 2, 8, 4, 9], fee = 2

输出88

解释: 能够达到的最大利润: 在此处买入 prices[0]=1prices[0] = 1;在此处卖出 prices[3]=8prices[3] = 8;在此处买入 prices[4]=4prices[4] = 4;在此处卖出 prices[5]=9prices[5] = 9

总利润: ((81)2)+((94)2)=8((8 - 1) - 2) + ((9 - 4) - 2) = 8

本题 # 122. 买卖股票的最佳时机2 仅差了手续费这一条件。每次交易(一买一卖为一次交易)就会有一笔手续费,故我们固定买卖股票是后收费,即买入时没有手续费,卖出股票时才会出现手续费。

中规中矩的动态规划

1、确定 dp 数组以及其含义

由于不能同时参与多笔交易,即必须卖出手中股票才能再次购买,亦或手中不持股时才能买入,因此每天交易结束后仅有两种情况,即,1、手中持股,2、手中不持股。

故,用动态规划数组 dp[i][j]dp[i][j] 表示第 ii 日持股状态为 jj 时,我们手上最大的收益,其中,

  • i[0,n),n=prices.lengthi \in [0, n), n = prices.length

  • j=0j = 0 或者 11,持股 (00),指不持股 (11)

2、确定 dp 对应的状态方程

如第 ii 天持股,即 dp[i][0]dp[i][0],存在两种可能:

👉 第 i1i-1 天也持股: dp[i1][0]dp[i-1][0]

👉 第 i1i-1 天不持股并在第 ii 天买入(此时无手续费):dp[i1][1]prices[i]dp[i-1][1] - prices[i]

故, dp[i][0]=max(dp[i1][0],dp[i1][1]prices[i])dp[i][0] = max(dp[i-1][0], dp[i-1][1] - prices[i])


如第 ii 天不持股,即 dp[i][1]dp[i][1],存在两种可能:

👉第 i1i-1 天也不持股: dp[i1][1]dp[i-1][1]

👉第 i1i-1 天卖出(此时有手续费): dp[i1][0]+prices[i]feedp[i-1][0] + prices[i] - fee

故,dp[i][1]=max(dp[i1][1],dp[i1][0]+prices[i]fee)dp[i][1] = max(dp[i-1][1], dp[i-1][0] + prices[i] - fee)

3、确定 dp 的初始状态

00 日持股与不持股的最大收益为: {dp[0][0]=prices[0],dp[0][1]=0\begin{cases} dp[0][0] = -prices[0], & \\ dp[0][1] = 0 \end{cases}

4、确定遍历顺序

从第 11 天一直遍历到第 n1n-1

5、确定最终返回值

最后一日肯定不能再持有股票了,如果持有股票,利润肯定不是最大的,故选择最后一日不持股的状态,即,dp[n1][1]dp[n - 1][1]

6、代码示例

/**
 * 空间复杂度 O(n),n是prices数组的长度
 * 时间复杂度 O(n)
 */
function maxProfit(prices: number[], fee: number): number {
    const len = prices.length;
    const dp = Array.from({ length: len }, () => [0, 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] = Math.max(dp[i - 1][1], dp[i - 1][0] + prices[i] - fee);
    }

    return dp[len - 1][1];
};

状态压缩

/**
 * 空间复杂度 O(1)
 * 时间复杂度 O(n)
 */
function maxProfit(prices: number[], fee: number): number {
    const len = prices.length;
    let dp0 = -prices[0];
    let dp1 = 0

    for(let i = 1; i < len; i++) {
        [ dp0, dp1 ] = [
            Math.max(dp0, dp1 - prices[i]),
            Math.max(dp1, dp0 + prices[i] - fee),
        ];
    }

    return dp1;
};

参考

至此 动规团灭股票买卖 就全部更新完毕啦...