121. 买卖股票的最佳时机
121. 买卖股票的最佳时机
题目来源
题目分析
给定一个数组
prices
,其中prices[i]
是一支给定股票第i
天的价格。设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
题目难度
- 难度:简单
题目标签
- 标签:动态规划
题目限制
- 1 <= prices.length <= 3 * 10^4
- 0 <= prices[i] <= 10^4
解题思路
思路:动态规划
-
问题定义:
- 本题要求通过选择适当的买入和卖出时机,计算在单次买卖操作中所能获得的最大利润。
-
核心算法:
- 动态规划:我们使用一个变量来记录当前遇到的最低价格,另一个变量来记录当前所能获得的最大利润。随着遍历股票价格数组,不断更新最低价格和最大利润。
-
关键步骤:
- 遍历数组时,更新最低价格
minPrice
和最大利润maxProfit
。 - 通过与当前价格计算差值来判断是否需要更新最大利润。
- 遍历数组时,更新最低价格
核心算法步骤
-
初始化变量:
minPrice
记录股票的最低价格,初始为prices[0]
。maxProfit
记录最大利润,初始为0
。
-
遍历价格数组:
- 对每个价格
price
,更新minPrice
为当前的最小价格。 - 计算
price - minPrice
并更新maxProfit
为当前最大利润。
- 对每个价格
-
返回结果:
- 遍历结束后,
maxProfit
即为最大利润。
- 遍历结束后,
代码实现
以下是动态规划法的 Java 代码实现:
/**
* 121. 买卖股票的最佳时机
* @param prices 股票价格数组
* @return 最大利润
* @apiNote 动态规划,时间复杂度O(n),空间复杂度O(1)
*/
public int maxProfit3(int[] prices) {
int minPrice = prices[0];
int maxProfit = 0;
for (int price : prices) {
minPrice = Math.min(minPrice, price);
maxProfit = Math.max(maxProfit, price - minPrice);
}
return maxProfit;
}
代码解读
- 初始化最低价格:
minPrice
被初始化为数组的第一个元素。 - 遍历更新:在遍历数组时,
minPrice
不断更新为当前遍历到的最低价格,maxProfit
则更新为当前价格与最低价格的差值中的最大值。 - 返回最大利润:循环结束后,
maxProfit
存储的即为最大利润。
性能分析
- 时间复杂度:
O(n)
,遍历一次数组即可获得最大利润。 - 空间复杂度:
O(1)
,只使用了常数级别的辅助空间。
复杂度效果
测试用例
你可以使用以下测试用例来验证代码的正确性:
// 测试用例1
int[] prices1 = {7, 1, 5, 3, 6, 4};
int result1 = maxProfit3(prices1);
System.out.println(result1); // 输出: 5
// 测试用例2
int[] prices2 = {7, 6, 4, 3, 1};
int result2 = maxProfit3(prices2);
System.out.println(result2); // 输出: 0
扩展讨论
优化写法
- 单次遍历法:通过单次遍历数组即可在
O(n)
时间复杂度下找到最大利润,这是时间最优解法。
其他实现
- 暴力法:通过两重循环枚举所有的买卖组合,时间复杂度为
O(n^2)
,不推荐。
总结
这道题目主要考察了对动态规划的理解,通过对最低价格的动态更新和利润的实时计算,可以在 O(n)
的时间复杂度内得到最优解。