《股票价格》题目分析
这道题目要求我们实现一个数据结构可以处理一种二元数据< timestamp, price >。
并其支持以下操作:
- 在队尾插入一条数据
- 删除timestamp小于等于给定值的数据,根据题意我们知道这些数据都在队首
- 查询price最高、最低和timestamp最大(队尾)的数据
其中1和2可以用队列实现,3可以用堆实现。但是我们要把队列和堆结合起来就有点难度。困难在于当我们从队首删除数据的时候,我们必须知道这些数据在堆中的位置,然后才能进行删除。有兴趣的同学可以自己实现一个完整的带索引的堆。
这里我们介绍一种利用set/map的平衡树特性(Java中的TreeMap和TreeSet, C#中的SortedSet和SortedDictionary, Python...)的做法。
首先我们用map<int, int> price
来保存每个timestamp的price是多少,也就是price[timestamp]
保存着timestamp时的价格。由于map内部是用红黑树实现的,所以我们从price.beign()
到price.end()
依次保存着timestamp从小到大的数据。
其次我们用multiset<int> prices
来保存没被删掉的数据的价格集合。同样由于set/multiset是由红黑树实现的,所以从prices.begin()
到prices.end()
从小到大一次保存着价格。(有些语言没有内置的多重集合,我们也可以用类似 set<pair<int, int>>
的方式存储,其中pair的第一关键字是price,第二关键字是timestamp。)
当我们遇到P指令时,只需将数据插入price和prices:
if(c == 'P') {
cin >> t >> p;
price[t] = p;
prices.insert(p);
}
当我们遇到删除时,只需要从头开始在price里找timestamp小于等于给定值的数据,然后再在price和prices里同时删除这些数据。虽然一次R操作可能删除掉多条数据,但是均摊下来每次操作只会删除一条数据,复杂度是O(logN)的。
if(c == 'R') {
cin >> t;
while(price.size() != 0 && price.begin()->first <= t) {
auto itr = prices.find(price.begin()->second);
prices.erase(itr);
price.erase(price.begin());
}
}
对于查询,最高价格保存在prices.begin()
,最低价格保存在prices.rbegin()
, 最近价格保存在price.rbegin()
。
if(c == 'Q') {
cout << *(prices.rbegin()) << ' ' << *(prices.begin()) << ' ' << price.rbegin()->second << endl;
}
有道理,你不提醒我都没想到。