给定一个整数数组 prices,其中第 i 个元素代表了第 i 天的股票价格 ;非负整数 fee 代表了交易股票的手续费用。
你可以无限次地完成交易,但是你每次交易都需要付手续费。如果你已经购买了一个股票,在卖出它之前你就不能再继续购买股票了。
返回获得利润的最大值。
示例 1:
输入: prices = [1, 3, 2, 8, 4, 9], fee = 2
输出: 8
解释: 能够达到的最大利润: 在此处买入 prices[0] = 1
在此处卖出 prices[3] = 8
在此处买入 prices[4] = 4
在此处卖出 prices[5] = 9
总利润: ((8 - 1) - 2) + ((9 - 4) - 2) = 8.
注意:
0 < prices.length <= 50000.
0 < prices[i] < 50000.
0 <= fee < 50000
解决这个问题的关键是要知道什么时候该卖出,利润就等于卖出时价格减去之前遍历到的最小值再减去手续费,利润很好计算。
那么怎么判断是该持有还是该卖出呢?
首先从第二个数开始遍历,如果它比第一个数小,那我们就不买第一天的,买第二天的股票(这个时候更新最小值min)。
再来继续遍历,如果第三天的价格比第二天的高呢?(这个时候更新最大值max)这个时候卖不卖?无论卖或者不卖都让人为难,因为你不知道后面价格是不是会更高。所以我们是否卖出股票应该由接下来的一天决定。
所以我们看第四天的,如果第四天比第三天还高,那我们就继续观望(继续更新max)。
第五天终于跌了,跌多少的时候卖出呢?假设之前的最小值为a,第四天(也就是跌之间的最大值)的价格为b,跌了之后价格为c,第二次卖出时价格为d。那么不卖出,也就是从a-d只交易一次利润为p1 = (d-a-fee),卖出,也就是交易两次利润为p2 =(b-a+d-c-2*fee),当交易两次利润比一次利润大时,我们在下跌的时候就应该卖出,p2-p1 = b-c-fee>0,也就是b-c>fee。所以当跌了的价格超过手续费时我们就应该卖出,这样就能进行多次交易获得更大的利润。
当遍历到末尾时,只要利润大于0就应该卖出。
class Solution {
public int maxProfit(int[] prices, int fee) {
int res = 0;
int min = prices[0];
int max = prices[0];
int cur = 0;
//min记录遍历到的最小值,max记录遍历到的最大值
//这个最难在于求什么时候卖出,取最小值为购买点,最大值减最小值即为利润
for(int i = 1; i < prices.length; i++) {
min = Math.min(min, prices[i]);
max = Math.max(max, prices[i]);
cur = Math.max(cur, prices[i] - min - fee);
//由上述公式推导得,当下跌超过手续费时,就应该卖出
if(max - prices[i] > fee) {
res += cur;
cur = 0;
min = prices[i];
max = prices[i];
}
}
res += cur;
return res;
}
}