一、题目
给定一个整数数组prices,其中第 prices[i] 表示第 i 天的股票价格 。
设计一个算法计算出最大利润。在满足以下约束条件下,你可以尽可能地完成更多的交易(多次买卖一支股票):
卖出股票后,你无法在第二天买入股票 (即冷冻期为 1 天)。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
示例 1:
输入: prices = [1,2,3,0,2]
输出: 3
解释: 对应的交易状态为: [买入, 卖出, 冷冻期, 买入, 卖出]
示例 2:
输入: prices = [1]
输出: 0
提示:
1 <= prices.length <= 5000
0 <= prices[i] <= 1000
二、代码
class Solution {
public int maxProfit(int[] prices) {
// 如果只有一个数,那么最大的收益肯定就是0
if (prices == null || prices.length < 2) {
return 0;
}
int n = prices.length;
// buy[i]指的是在0到i的范围上,最后一次操作一定是买操作能拿到的最大收益。
int[] buy = new int[n];
// sell[i]指的是0~i做无限制次数的交易,最后一个动作必须是卖,能获得的最好收入。
int[] sell = new int[n];
// i=0的时候,我们在0~0选择一个买入时间,只有一个时间点0,所以只能选0时间点买入,但是0之前已经没有别的时间点了,也就是说在0买入时间之前的最大收益就是0,所以buy[0] = 0 -prices[0]
buy[0] = -prices[0];
// 取两种情况的最大值
// 情况1:1不参与交易,buy[1] = buy[0]
// 情况2:1参与交易,buy[1] = 0 - prices[1]
buy[1] = Math.max(buy[0], -prices[1]);
// 如果0位置是卖出操作,前面必须要有买入操作才可以,但是0前面已经没有时间点了,不可能有买入操作,所以sell[0]这个情况本身就是不存在的,直接设置为0。
sell[0] = 0;
// 取两种情况的最大值
// 情况1:1不参与交易,sell[1] = sell[0]
// 情况2:1参与交易,sell[1] = buy[0] + prices[1]
sell[1] = Math.max(sell[0], buy[0] + prices[1]);
// 开始构造buy和sell
for (int i = 2; i < n; i++) {
// 取两种情况的最大值 因为卖操作之后需要冻结一天才可以再买,所以这里用sell[i - 2]
buy[i] = Math.max(buy[i - 1], sell[i - 2] - prices[i]);
// 取两种情况的最大值
// 我们能发现sell是依赖buy求出来的 买操作之后并不需要冻结一天,所以这里用buy[i - 1]
sell[i] = Math.max(sell[i - 1], buy[i - 1] + prices[i]);
}
// 最后的结果就是0~n-1位置去进行交易,并且保证最后一次操作一定是卖的情况下的最高收益
return sell[n - 1];
}
}
三、解题思路
这道题优化的关键就是引入了buy数组和sell数组。
buy[i]:指的是在0到i的范围上,最后一次操作一定是买操作能拿到的最大收益。这个买操作的时间点并不一定是i,可以是0~i上的任意时间点。buy[i]的值就会在0~i范围上选择一个最后买入的时间点,能够使i之前的最大收益减去i买入的价格得到的结果最大,这个最大值就是buy[i]。
sell数组的思路和buy数组就基本差不多了。sell[i]:0~i做无限制次数的交易,最后一个动作必须是卖,能获得的最好收入。