122. 买卖股票的最佳时机 II
问题描述
给定一个数组 prices,其中 prices[i] 表示某支股票第 i 天的价格。你可以多次买卖这支股票,但必须在再次购买前卖出之前的股票。计算你能获得的最大利润。
示例
1 2 3 4 5 6
| 输入: prices = [7,1,5,3,6,4] 输出: 7 解释: - 第2天买入(1),第3天卖出(5),利润 = 5-1 = 4 - 第4天买入(3),第5天卖出(6),利润 = 6-3 = 3 总利润 = 4 + 3 = 7
|
方法一:贪心算法
核心思想
- 只要今天的价格比昨天高,就进行交易(昨天买入,今天卖出)。
- 因为可以多次交易,所有正利润的累加就是最大利润。
代码
1 2 3 4 5 6 7 8 9
| var maxProfit = function(prices) { let profit = 0; for (let i = 1; i < prices.length; i++) { if (prices[i] > prices[i - 1]) { profit += prices[i] - prices[i - 1]; } } return profit; };
|
复杂度分析
- 时间复杂度:O(n),只需遍历一次数组。
- 空间复杂度:O(1),仅用常数空间。
方法二:动态规划
核心思想
- 状态定义:
dp[i][0]:第 i 天结束时未持有股票的最大利润。
dp[i][1]:第 i 天结束时持有股票的最大利润。
- 状态转移:
dp[i][0] = max(dp[i-1][0], dp[i-1][1] + prices[i])
(前一天未持有,或前一天持有今天卖出)
dp[i][1] = max(dp[i-1][1], dp[i-1][0] - prices[i])
(前一天持有,或前一天未持有今天买入)
代码
1 2 3 4 5 6 7 8 9 10 11 12
| var maxProfit = function(prices) { const n = prices.length; const dp = new Array(n).fill(0).map(() => [0, 0]); dp[0][0] = 0; dp[0][1] = -prices[0]; for (let i = 1; i < n; i++) { dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] + prices[i]); dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] - prices[i]); } return dp[n - 1][0]; };
|
优化空间
1 2 3 4 5 6 7 8 9 10
| var maxProfit = function(prices) { let [hold, notHold] = [-prices[0], 0]; for (const p of prices) { [hold, notHold] = [ Math.max(hold, notHold - p), Math.max(notHold, hold + p) ]; } return notHold; };
|
复杂度分析
- 时间复杂度:O(n)。
- 空间复杂度:O(1)(优化后)。
方法对比
| 方法 |
时间复杂度 |
空间复杂度 |
适用场景 |
| 贪心 |
O(n) |
O(1) |
简单高效,直接累加利润 |
| 动态规划 |
O(n) |
O(n) 或 O(1) |
通用性强,可扩展性高 |
关键点总结
- 贪心算法:
- 核心是 “所有正利润之和”,适用于本题的无限次交易。
- 动态规划:
- 通过状态转移方程覆盖所有可能操作,适合更复杂的股票问题(如含手续费、冷冻期等)。
最终推荐
- 直接使用贪心算法(代码简洁,效率高):
1 2 3 4 5 6 7 8 9
| var maxProfit = function(prices) { let profit = 0; for (let i = 1; i < prices.length; i++) { if (prices[i] > prices[i - 1]) { profit += prices[i] - prices[i - 1]; } } return profit; };
|