一、题目描述
给定一个数组,它的第 i
个元素是一支给定的股票在第 i
天的价格。
设计一个算法来计算你所能获取的最大利润。你最多可以完成 两笔 交易。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
示例 1:
输入:prices = [3,3,5,0,0,3,1,4] 输出:6 解释:在第 4 天(股票价格 = 0)的时候买入,在第 6 天(股票价格 = 3)的时候卖出,这笔交易所能获得利润 = 3-0 = 3 。 随后,在第 7 天(股票价格 = 1)的时候买入,在第 8 天 (股票价格 = 4)的时候卖出,这笔交易所能获得利润 = 4-1 = 3 。
示例 2:
输入:prices = [1,2,3,4,5] 输出:4 解释:在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。 注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。 因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。
示例 3:
输入:prices = [7,6,4,3,1] 输出:0 解释:在这个情况下, 没有交易完成, 所以最大利润为 0。
示例 4:
输入:prices = [1] 输出:0
提示:
1 <= prices.length <= 10^5
0 <= prices[i] <= 10^5
二、解题思路
这个问题是典型的动态规划问题。我们需要找到最大利润,但这次我们最多可以进行两笔交易。我们可以用动态规划来跟踪在每一天结束时,我们能获得的最大利润。
我们需要定义以下状态变量:
buy1
:第一次购买股票后的最大利润。sell1
:第一次卖出股票后的最大利润。buy2
:第二次购买股票后的最大利润。sell2
:第二次卖出股票后的最大利润。
初始状态:
buy1
= -prices[0](我们在第一天买入股票)sell1
= 0(我们还没有卖出股票)buy2
= -prices[0](我们在第一天买入股票,然后再次买入)sell2
= 0(我们还没有进行第二次卖出)
对于每一天,我们需要更新这些状态变量:
buy1
= max(buy1
, -prices[i])(我们保持当前的最大亏损或在新低价时买入)sell1
= max(sell1
,buy1
+ prices[i])(我们保持当前的最大利润或在高价时卖出)buy2
= max(buy2
,sell1
- prices[i])(我们在第一次卖出后,在低价时再次买入)sell2
= max(sell2
,buy2
+ prices[i])(我们在第二次买入后,在高价时卖出)
最终答案是sell2
。
三、具体代码
class Solution {
public int maxProfit(int[] prices) {
if (prices == null || prices.length == 0) {
return 0;
}
int buy1 = -prices[0], sell1 = 0;
int buy2 = -prices[0], sell2 = 0;
for (int i = 1; i < prices.length; i++) {
buy1 = Math.max(buy1, -prices[i]);
sell1 = Math.max(sell1, buy1 + prices[i]);
buy2 = Math.max(buy2, sell1 - prices[i]);
sell2 = Math.max(sell2, buy2 + prices[i]);
}
return sell2;
}
}
四、时间复杂度和空间复杂度
1. 时间复杂度
- 我们可以看到,代码中有一个循环,这个循环会遍历一次给定的数组
prices
。 - 在循环内部,我们执行了四个基本操作,每个操作都是常数时间的操作,如比较和赋值。
- 因此,循环的每次迭代都是常数时间的,即O(1)。
- 由于循环执行了
prices.length - 1
次迭代(从索引1开始到prices.length - 1
),所以总的时间复杂度是O(n),其中n是数组prices
的长度。
2. 空间复杂度
- 我们在代码中定义了四个整型变量
buy1
、sell1
、buy2
和sell2
来存储每一步的最大利润状态。 - 这些变量使用的空间是常数大小的,与输入数组
prices
的大小无关。 - 因此,不管输入数组
prices
有多大,我们所使用的额外空间都是固定的,即O(1)。
综上所述,代码的时间复杂度是O(n),空间复杂度是O(1)。
五、总结知识点
1. 基本编程概念:
- 变量定义:代码中定义了四个整型变量来存储买入和卖出的最大利润。
- 循环结构:使用for循环来遍历数组
prices
中的每个元素。
2. 数组操作:
- 访问数组元素:通过索引
i
访问数组prices
中的元素。
3. 数学运算:
- 最大值比较:使用
Math.max()
函数来比较并保留最大值。
4. 算法思想:
- 动态规划:使用动态规划的思想来逐步计算最大利润,而不是暴力搜索所有可能的交易组合。
5. 动态规划状态定义:
buy1
和sell1
:分别代表第一次买入和卖出股票后的最大利润。buy2
和sell2
:分别代表第二次买入和卖出股票后的最大利润。
6. 边界条件处理:
- 检查输入数组是否为空或长度为0,如果是,则直接返回
以上就是解决这个问题的详细步骤,希望能够为各位提供启发和帮助。