返回

LeetCode 188:拥抱买卖股票的终极指南——深入浅出,实战攻略

IOS

前言

对于程序员和算法爱好者来说,LeetCode 是一块广受认可的磨刀石,其精心设计的算法题库为挑战者提供了绝佳的训练场。其中,LeetCode 188 买卖股票的最佳时机 IV 堪称一道经典题,它要求我们求解在给定的交易限制下,在给定的股票价格数组中买卖股票以获得最大利润。

算法概述

LeetCode 188 是一道动态规划问题,它要求我们使用动态规划技术来解决买卖股票的最佳时机问题。动态规划是一种解决问题的技术,它将问题分解成较小的子问题,并使用这些子问题的最优解来逐步求解整个问题。

对于 LeetCode 188,我们将使用一个二维表来存储买卖股票的最佳时机和收益。该表中的每一行代表交易次数,每一列代表股票持有状态(持有股票或不持有股票)。通过填充此表,我们可以逐步求解问题的最优解。

解决方案

1. 状态定义

我们定义一个二维表 dp,其中:

  • dp[i][j] 表示在进行 i 次交易且在 j 状态下(0 表示不持有股票,1 表示持有股票)的最大利润。

2. 状态转移方程

状态转移方程了如何从一个状态转移到另一个状态:

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])

其中:

  • prices[i] 表示第 i 天的股票价格。
  • fee 表示每次交易产生的费用。

3. 初始化

我们将二维表 dp 的第一行初始化为 0,表示没有交易时利润为 0。

for (int j = 0; j < k+1; j++) {
    dp[0][j] = 0;
}

4. 状态转移

对于每一行 i 和每一列 j,我们根据状态转移方程更新 dp 表:

for (int i = 1; i < n+1; i++) {
    for (int j = 1; j < k+1; j++) {
        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 表的最后一行、第一列中:

return dp[n][0];

实例讲解

假设我们有以下股票价格数组:

prices = [1, 2, 3, 4, 5]

交易次数限制为 k = 2,交易费用为 fee = 2

使用动态规划算法,我们得到以下 dp 表:

交易次数 持有状态 最大利润
0 不持有股票 0
0 持有股票 -2
1 不持有股票 0
1 持有股票 -2
2 不持有股票 2
2 持有股票 -4
3 不持有股票 4
3 持有股票 -6
4 不持有股票 6

最终结果为 dp[4][0] = 6,表示在进行两次交易且交易费用为 2 的情况下,我们可以获得的最大利润为 6。

扩展与应用

LeetCode 188 算法不仅可以解决股票问题,还可以扩展到其他类似问题,例如:

  • 买卖股票的最佳时机 V :允许至多 k 次交易,但每次交易之间需要有冷却期。
  • 买卖股票的最佳时机 VI :股票价格数组中包含一些未知信息。
  • 买卖股票的最佳时机 VII :股票价格数组中包含一些交易限制。

总结

LeetCode 188 买卖股票的最佳时机 IV 是算法题库中的一道经典题,它考察了我们的动态规划能力。通过使用二维表和状态转移方程,我们可以逐步求解问题的最优解。通过理解算法背后的原理和实践操作,我们不仅可以解决这道题,还可以将其扩展到其他类似问题,从而提升我们的算法技能和解决问题的能力。