122.买卖股票 II 
动态规划
dp 数组含义
题目允许完成多笔交易,但同一时间最多只能持有一只股票。也就是说,必须先卖出手里的股票,才能再次买入。
每天结束后,手里只有两种状态:
这里的“第 i 天结束后”表示第 i 天的买入、卖出、什么都不做这些选择都已经考虑完了。
最终答案应该是不持有股票的最大利润:
因为最后如果还持有股票,说明这只股票还没有卖出,利润不会最大。
确定状态转移方程
第 i 天结束后不持有股票
dp[i][0] 有两种来源:
- 昨天就不持有股票,今天什么都不做:
- 昨天持有股票,今天卖出:
所以:
第 i 天结束后持有股票
dp[i][1] 也有两种来源:
- 昨天就持有股票,今天继续持有:
- 昨天不持有股票,今天买入:
本题允许多次交易,所以今天买入时,可以继承昨天不持股状态下已经获得的利润。
所以:
这也是本题和“121. 买卖股票的最佳时机”的核心区别:
- 121 只能交易一次,买入时写
-prices[i]。 - 122 可以交易多次,买入时写
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,卖出可以获得利润4,所以dp[2][0] = 4。 - 第
3天价格为3,可以用之前赚到的4再买入,利润变成4 - 3 = 1,所以dp[3][1] = 1。 - 第
4天价格为6,卖出后利润变成1 + 6 = 7,所以dp[4][0] = 7。
最终答案:
也就是先在 1 买入、5 卖出,再在 3 买入、6 卖出,最大利润为 4 + 3 = 7。
代码实现
复杂度分析
- 时间复杂度:
O(n),只遍历一次价格数组。 - 空间复杂度:
O(n),使用dp数组保存每天的两个状态。
空间优化
因为第 i 天只依赖第 i - 1 天,所以可以用两个变量保存状态。
贪心算法
解题思路
本题允许完成多笔交易,并且没有手续费、冷冻期等额外限制。因此,只要后一天的价格比前一天高,就可以收集这两天之间的上涨利润:
遍历价格数组,把所有大于 0 的相邻价格差累加起来,就是能够获得的最大利润。
为什么只收集正利润
假设股票价格连续上涨:
在价格为 1 时买入、价格为 6 时卖出,利润为:
也可以把这段上涨拆成相邻两天的利润:
两种计算方式的结果完全相同。因此,一段连续上涨行情可以被拆成每一天的正利润,拆分后不会少赚。
如果相邻两天的价格下降,例如:
这段交易会产生亏损,可以直接跳过。由于交易次数不限,后面再次上涨时仍然可以买入,不会影响后续交易。
所以贪心策略是:
举例推导
以 prices = [7, 1, 5, 3, 6, 4] 为例:
最终利润为:
对应的实际交易是:
代码实现
也可以使用 Math.max 简化判断:
与第 121 题的区别
- 第 121 题最多只能完成一笔交易,所以需要维护历史最低价格,寻找最大的一段上涨利润。
- 第 122 题可以完成多笔交易,所以可以收集所有相邻两天之间的正利润。
这个贪心策略成立的前提是:交易次数不限,并且没有手续费、冷冻期等额外限制。如果题目加入这些条件,就不能直接累加所有正价格差。
复杂度分析
- 时间复杂度:
O(n),只遍历一次价格数组。 - 空间复杂度:
O(1),只使用一个变量累计利润。


