返回

动态规划征服 LeetCode:巧解买卖股票最佳时机带手续费

后端

引言:算法之美,动态规划之妙

算法,计算机科学皇冠上的明珠,以其严谨的逻辑和强大的计算能力,成为解决复杂问题的利器。而动态规划,作为算法家族中的一颗璀璨之星,更是以其独到的视角和强大的优化能力,在众多领域大放异彩。LeetCode,算法爱好者的圣地,汇聚了海量的算法题库,其中买卖股票最佳时机系列问题更是备受推崇,吸引了无数算法爱好者竞折腰。

问题陈述:买卖股票的最佳时机(含手续费)

在现实世界中,股票交易是一项复杂的投资活动。投资者需要把握时机,在股票价格波动的起伏中寻找获利机会。然而,在实际交易中,除了股票价格的涨跌,还需要考虑交易手续费对收益的影响。LeetCode 中的买卖股票最佳时机(含手续费)问题正是模拟了这一场景,要求我们计算在给定股票价格序列和交易手续费的情况下,如何安排买入和卖出股票以实现最大收益。

动态规划:化繁为简,逐层递进

动态规划是一种强大的算法技术,它将复杂问题分解成一系列子问题,并通过逐步求解子问题,最终解决原问题。在买卖股票最佳时机(含手续费)问题中,我们可以将问题分解为以下子问题:

  • 在第 i 天,处于不持有股票的状态,最大收益是多少?
  • 在第 i 天,处于持有股票的状态,最大收益是多少?

状态转移方程:巧用递推,步步为营

根据上述子问题,我们可以建立状态转移方程:

  • 不持有股票状态: 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])

其中,dp[i][0]dp[i][1]分别表示在第i天处于不持有股票和持有股票状态下的最大收益。prices[i]为第i天的股票价格,fee为交易手续费。

代码实现:算法之美,代码之魂

public int maxProfit(int[] prices, int fee) {
    int n = prices.length;
    int[][] dp = new int[n][2];
    dp[0][0] = 0;
    dp[0][1] = -prices[0];
    for (int i = 1; i < n; i++) {
        dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] + prices[i] - fee);
        dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] - prices[i]);
    }
    return dp[n - 1][0];
}

示例解析:庖丁解牛,深入浅出

假设股票价格序列为[1, 3, 2, 8, 4, 9],交易手续费为2

  • 第 1 天: 不持有股票,最大收益为0;持有股票,最大收益为-1(买入股票花费1元)。
  • 第 2 天: 不持有股票,最大收益为0(继续不持有);持有股票,最大收益为-3(买入股票花费3元)。
  • 第 3 天: 不持有股票,最大收益为3(卖出股票,赚取3-2元利润);持有股票,最大收益为-3(继续持有)。
  • 第 4 天: 不持有股票,最大收益为6(买入股票,花费8-2元);持有股票,最大收益为-7(买入股票花费9-2元)。
  • 第 5 天: 不持有股票,最大收益为6(继续不持有);持有股票,最大收益为-9(买入股票花费11-2元)。
  • 第 6 天: 不持有股票,最大收益为9(卖出股票,赚取9-2元利润);持有股票,最大收益为-9(继续持有)。

最终,我们在不持有股票的情况下获得最大收益9元。

总结:算法之钥,思维之匙

动态规划是一种强大的算法技术,它通过将复杂问题分解成一系列子问题,并逐步求解子问题,最终解决原问题。在买卖股票最佳时机(含手续费)问题中,我们可以将问题分解为不持有股票和持有股票两种状态,并建立状态转移方程来求解子问题。通过代码实现,我们可以高效地计算出在给定股票价格序列和交易手续费的情况下,如何安排买入和卖出股票以实现最大收益。