题目描述
给定一个整数数组 prices 表示股票的价格,第 i 个元素表示第 i 天的股票价格,同时给定 fee 表示进行一次股票交易需要承担的费用。
允许进行多次股票交易,但每次交易都需要承担 fee 的费用。并且你在某一时刻只允许拥有一支股票。
要求返回能获得的最大利益。原题以及例子如下,
关于这种选择类的问题,最容易想到的便是枚举出所有的可能,然后选出最大的利益,要实现这种方法可以使用二叉树的方法,因为每个结点能做出两种选择,买或者卖,代表着二叉树的两个分支,用二叉树能很容易的枚举出所有可能,但显然用这种方法的代价过于高昂,但这不失为提供思路的好方法。这里我们考虑如何减少树每层结点的个数,从而优化算法的时间复杂度。
首先我们考虑整个购买股票的流程,每一次购买股票,代表新的一次交易开始,那么此时购买股票的profit要大于我上次购买股票时的profit,才会选择购买新的股票,即上一组买卖股票的结束(这里不用担心如果上一次股票未卖出时便再次购买股票,因为如果在上一次股票还未卖出的情况下,这一次购买股票得到的profit一定是小于上一次的,如果不理解可以自己用下面的公式试试)。同理当这次出售股票获取的profit大于上一次时,才卖出股票。下面我用pre-Buy和buy分别表示上一次购买和这一次购买时获得的profit,pre-Sell和sell分别代表上一次出售股票和这次出售股票获得的profit。这里要注意到一个细节,我计算pre-Sell时,是用pre-Buy+currentPrice,这意味着,如果在未买入新股票的情况下,会持续比较是否在其他时刻出售股票,使得buy大于pre-Buy。在这种情况下,我们就不用考虑每一层所有结点的情况,每一层只用考虑1个结点,即时间复杂度为O(n)。
sell = pre-Buy + currentPirce;
buy = pre-Sell - currentPrice - fee;
pre-Sell = Max(pre-Sell, sell);
pre-Buy = Max(pre-Buy, buy);
如果还是不理解,建议多举几个例子,代入试试。
下面是源代码,
class Solution {
public:
int maxProfit(vector<int>& prices, int fee) {
int buy = INT_MIN, sell = 0;
for (int price : prices) {
int tmp = sell;
sell = max(sell, buy + price);
buy = max(buy, tmp - price - fee);
}
return sell;
}
};
另外这里还有另外一种比较繁琐的写法,如果不理解上一种写法,可以看看这种,源码如下,
class Solution {
public:
int maxProfit(vector<int>& prices, int fee) {
int l = prices.size();
if (l == 0) return 0;
int maxx = prices[l - 1];
int minn = prices[l - 1];
int sum = 0;
bool isUsed = false;
for (int i = l - 2; i >= 0; --i) {
if (prices[i] > minn + fee || prices[i] > maxx) {
if (maxx - minn - fee > 0) {
sum += maxx - minn - fee;
isUsed = true;
}
maxx = prices[i];
minn = prices[i];
isUsed = false;
} else {
minn = min(minn, prices[i]);
}
}
if (!isUsed && maxx - minn - fee > 0) {
sum += maxx - minn - fee;
}
return sum;
}
};