-
题目:
数组prices的每个元素prices [ i ]代表每天的价格,选择买入卖出时机,返回最多赚的钱; -
思路:
1.贪心:O(n),O(1)
本题用贪心解决的话,关注点并不在具体的买入和卖出日期上,而是将利润分解开计算的,但分解开的这些操作与实际操作其实也是有一定对应关系的;
minPrice并不一定是真正实际操作时的买入价格:实际一笔交易的利润,在计算时可能会被分解开,minPrice充当每一次计算利润时的买入价格;
每次计算利润时,都会扣手续费。若一笔实际交易只对应一次利润计算,这样刚好; 但若一笔实际交易对应多次利润计算,则需要提前弥补minPrice,防止后面几次多次扣手续费。
在每次计算利润后,minPrice = prices[i] - fee,这句很重要。后面可能还是同一笔交易的利润计算,也有可能遇到更低的prices[ ] 值,说明前面这笔交易确实结束了,又将进行一笔新交易;
class Solution {
public:
int maxProfit(vector<int>& prices, int fee) {
int res = 0;
int minPrice = prices[0]; //记录最低价格
for (int i = 1; i < prices.size(); ++i) {
//说明价格很低就买入
minPrice = prices[i] < minPrice ? prices[i] : minPrice;
//说明价格比minPrice高,但高的不多,此时卖则亏本,买也不便宜
if (prices[i] >= minPrice && prices[i] <= minPrice + fee) continue;
//说明价格比minPrice高很多,就计算一次利润(扣手续费),但这不代表真正卖出操作;
//若对应到实际操作相当于一笔实际交易分为几次利润计算,手续费在第一次计算时就扣了,后面计算利润时相当于降低了买入价格
if (prices[i] > minPrice + fee) {
res += prices[i] - (minPrice + fee);//一笔交易只扣一次手续费
minPrice = prices[i] - fee; //对于连续利润,在第一天计算利润时已经扣了一次手续费,因此后续几天不能再扣了
}
}
return res;
}
};
2.DP:O(n),O(1)
滚动记录前一天的两个值,用于更新今天的两个值;
class Solution {
public:
int maxProfit(vector<int>& prices, int fee) {
int holdStack_Max = (-1) * prices[0]; //持有股票时的最多现金
int noStack_Max = 0; //不持有股票时的最多现金
for (int i = 1; i < prices.size(); ++i) {
int pre_holdStack_Max = holdStack_Max; //备份一下,因为下面改了holdStack_Max后,noStack_Max还要用
holdStack_Max = max(holdStack_Max, noStack_Max - prices[i]);
noStack_Max = max(noStack_Max, holdStack_Max + prices[i] - fee); //在卖出时扣手续费
}
return noStack_Max;
}
};
- 总结:
本题贪心需要考虑清楚细节,但DP有点黑盒子的感觉