121.买卖股票的最佳时机
动态规划
dp 数组含义
题目要求最多只完成一笔交易,也就是只能买入一次、卖出一次。
每天结束后,手里只有两种状态:
这里的“第 i 天结束后”表示当天的操作已经考虑完了。当天可以选择买入、卖出,或者什么都不做。
最终答案应该是不持有股票的最大利润,也就是:
如果最后还持有股票,说明只买了没有卖,利润不会是最终答案。
确定状态转移方程
第 i 天结束后不持有股票
dp[i][0] 有两种来源:
- 昨天就不持有股票,今天什么都不做:
- 昨天持有股票,今天卖出:
所以:
第 i 天结束后持有股票
dp[i][1] 也有两种来源:
- 昨天就持有股票,今天继续持有:
- 今天第一次买入股票:
本题最多只能完成一笔交易,所以买入之前的利润只能是 0,不能写成 dp[i - 1][0] - prices[i]。如果那样写,就表示可以把之前卖出的利润继续拿来买第二次股票了。
所以:
dp 数组如何初始化
第 0 天只有一个价格 prices[0]。
含义:
dp[0][0] = 0:第0天结束后不持有股票,说明什么都没做,利润是0。dp[0][1] = -prices[0]:第0天结束后持有股票,说明在第0天买入了股票,利润是负的买入价格。
如果 prices 为空,没有任何交易可以做,直接返回 0。
确定遍历顺序
dp[i][0] 依赖:
dp[i][1] 依赖:
当前第 i 天的状态都依赖前一天的状态,所以遍历顺序是从前往后:
举例推导
以 prices = [7, 1, 5, 3, 6, 4] 为例。
初始化:
完整 dp 数组变化如下:
解释几个关键位置:
- 第
1天价格为1,此时买入更便宜,所以dp[1][1] = -1。 - 第
2天价格为5,如果卖出,利润是5 - 1 = 4,所以dp[2][0] = 4。 - 第
4天价格为6,如果卖出,利润是6 - 1 = 5,所以dp[4][0] = 5。
最终答案:
也就是在价格为 1 时买入,价格为 6 时卖出,最大利润为 5。
代码实现
复杂度分析
- 时间复杂度:
O(n),只遍历一次价格数组。 - 空间复杂度:
O(n),使用dp数组保存每天的两个状态。
空间优化
因为第 i 天只依赖第 i - 1 天,所以可以用两个变量代替整个 dp 数组。
贪心算法
解题思路
要想在第 i 天卖出股票并获得尽可能多的利润,买入价格应该是第 0 天到第 i - 1 天之间的最低价格。
因此遍历价格数组时,只需要维护两个变量:
对于每天的价格 prices[i]:
- 假设今天卖出,利润为
prices[i] - minPrice,用它更新最大利润。 - 用今天的价格更新最低买入价格,为后面的卖出做准备。
每一天都选择此前最低的价格作为买入点,这是当前卖出日期下的最优选择;遍历所有可能的卖出日期后,就能得到全局最大利润。
举例推导
以 prices = [7, 1, 5, 3, 6, 4] 为例:
最终最大利润为 5。
代码实现
复杂度分析
- 时间复杂度:
O(n),只遍历一次价格数组。 - 空间复杂度:
O(1),只使用两个变量。


