前言
股票买卖问题是 LeetCode 中经典的动态规划题型,通常要求在给定的股价数组中,通过买入和卖出股票来获取最大利润。这类问题考验程序员对动态规划和贪心算法的理解和应用。
问题类型分类
股票买卖问题主要包括以下几种典型场景:
单次交易
- 问题描述:只能进行一次买入和卖出交易
- 解题关键:找出买入点和卖出点的最大利润差
多次交易(不限制交易次数)
- 问题描述:可以进行多次买卖,但每次只能持有一股
- 解题关键:贪心算法,只要存在利润就进行交易
有冷却期的多次交易
- 问题描述:卖出股票后,需要休息一定天数才能继续交易
- 解题关键:增加状态转移的复杂性,需要记录冷却状态
有手续费的多次交易
- 问题描述:每次交易需要扣除手续费
- 解题关键:在计算利润时需要减去手续费
最多进行K次交易
- 问题描述:限制最大交易次数
- 解题关键:需要使用更复杂的动态规划状态转移
解题模板与思路
动态规划通用思路
- 定义状态数组
- 确定状态转移方程
- 初始化边界条件
- 计算最终结果
单次交易示例代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| def maxProfit(prices): if not prices: return 0 min_price = float('inf') max_profit = 0 for price in prices: min_price = min(min_price, price) max_profit = max(max_profit, price - min_price) return max_profit
|
多次交易示例代码
1 2 3 4 5 6 7 8
| def maxProfit(prices): profit = 0 for i in range(1, len(prices)): if prices[i] > prices[i-1]: profit += prices[i] - prices[i-1] return profit
|
冷却期交易示例代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| def maxProfit(prices): if len(prices) < 2: return 0 dp = [[0, 0, 0] for _ in range(len(prices))] dp[0][2] = -prices[0] for i in range(1, len(prices)): dp[i][0] = max(dp[i-1][0], dp[i-1][1]) dp[i][1] = dp[i-1][2] + prices[i] dp[i][2] = max(dp[i-1][2], dp[i-1][0] - prices[i]) return max(dp[-1][0], dp[-1][1])
|
K次交易示例代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| def maxProfit(k, prices): if not prices or k == 0: return 0 if k >= len(prices) // 2: return sum(max(0, prices[i] - prices[i-1]) for i in range(1, len(prices))) dp = [[[0, float('-inf')] for _ in range(k + 1)] for _ in range(len(prices))] for j in range(k + 1): dp[0][j][1] = -prices[0] for i in range(1, len(prices)): for j in range(1, k + 1): dp[i][j][0] = max(dp[i-1][j][0], dp[i-1][j][1] + prices[i]) dp[i][j][1] = max(dp[i-1][j][1], dp[i-1][j-1][0] - prices[i]) return max(dp[-1][j][0] for j in range(k + 1))
|
含手续费的交易示例代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| def maxProfit(prices, fee): if len(prices) < 2: return 0 dp = [[0, 0] for _ in range(len(prices))] dp[0][1] = -prices[0] for i in range(1, len(prices)): 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]) return dp[-1][0]
|
解题技巧
贪心vs动态规划
状态定义
- 通常定义两个状态:持有股票和不持有股票
- 记录每个状态下的最大利润
边界处理
常见误区
- 忽略边界条件
- 没有正确处理状态转移
- 未考虑交易限制条件
后记
股票买卖问题是动态规划的经典应用,需要仔细分析问题的具体约束条件,选择合适的算法策略。通过反复练习和总结,可以逐步掌握解题的核心思路。