题目:
在某一天,你突然获得了可以预知每一天股票价格的超能力。在 第 i (i≤n)天,股票的价格为 a
i,每一天你只能选择买入或卖出一只股票,或者什么都不做。请聪明的你思考一下,如何操作才能使赚到的钱最多呢?
思路:
不同于其他几种股票问题这道题,他是可以同时多次买入,然后卖出,最终算出最大的获利,按一开始的思路我是采取将每一天股票的钱数和对应钱数的天数保存,然后按钱数从小到大排序,之后我们从最小开始遍历,然后我们用在末端放一指针,我们从后往前搜索,找到天数大于左端遍历位置的天数,将其股票赚的钱加到我们的总和当中,并将两个值抛出,如果直到该指针指向当前左端的遍历位置说明左端的这个值,它的天数太大,没有盈利的可能,遍历结束。循环这个过程直到整个数组中不存在盈利的可能或者所有数据都被抛出。但这样做的时间复杂度是O(n^2)太大了。所以我们采取反悔贪心的思想。购买股票的时候,我们每一天只能是买或者卖,或者什么都不做。在我们遍历每一天的股票情况时我们不妨将每一次遍历的值放到最小堆中,以便于我们可以在最小堆中找出前几天中最盈利的股票买入方案。如果我们发现当天股票与堆顶相比可以盈利我们就将其盈利的值加入到我们的盈利总和中去,并且将堆顶抛出,然后我们再将当天股票的价格放入最小堆中,我们发现我们会发生重复现象,这个情况就是反悔贪心的关键所在,因为如果后面几天出现更佳的卖出方案,我们再次放入的股票价格这个时候就充当了中间值的作用,它相当于代表了你买过了更便宜的股票,并且盈利已经加入到我们的盈利总和中去了。我们按更佳的值卖出时相当于是买入那个更便宜的股票(但它已经不在最小堆中了)并以更佳的价格卖出了。所以这个再次放入堆的操作是我们可能会后悔卖出,这也是反悔贪心的思维。我们这样最后时间复杂度就会变为O(n*logn)。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
int n;cin>>n;
int a[n];
for(int i=0;i<n;i++)
{
cin>>a[i];
}
ll sum=0;
priority_queue<int,vector<int>,greater<int>>que;
for(int i=0;i<n;i++)
{
que.push(a[i]);
if(!que.empty()&&a[i]>que.top())
{
sum+=a[i]-que.top();
que.pop();
que.push(a[i]);
}
}
cout<<sum;
}