考点
- 哈希表
- 红黑树
题意
设计一个算法,实现以下四个操作:
- 更新:给定时间戳和对应的股票价格(不按照时间顺序排列),更新股票在某一时间戳的股票价格,如果有之前同一时间戳的价格,这一操作将更正之前的错误价格。
- 找到当前记录里最新股票价格。最新股票价格定义为时间戳最晚的股票价格。
- 找到当前记录里股票的最高价格 。
- 找到当前记录里股票的最低价格 。
思路
要得到最新股票价格很容易,只需要维护一个curPrice和curTimestamp,每当有新记录输入的时候,比较一下时间戳,如果timestamp>=curTimestamp,更新即可。
最高和最低价格的获取则相对复杂。原因在于更新记录可能导致原有的价格被替换,也就是说,在排序的同时还存在频繁的插入和删除操作。
这就不得不提到我们伟大的面试杀手红黑树了:
红黑树是一种特化的AVL树(平衡二叉树),都是在进行插入和删除操作时通过特定操作保持二叉查找树的平衡,从而获得较高的查找性能。
它虽然是复杂的,但它的最坏情况运行时间也是非常良好的,并且在实践中是高效的: 它可以在O(log n)时间内做查找,插入和删除(这里的n是树中元素的数目)。
c++里的map内部就是基于红黑树实现的,因此插入的时候会对键值进行自动排序。
与之相对的是unordered_map,内部用哈希表实现,不会根据key值大小进行排序。
map | unordered_map | |
---|---|---|
实现机理 | 红黑树 | 哈希表 |
内部元素有序性 | 有序 | 无序 |
运行效率 | 可以在O(log n)时间内做查找,插入和删除 | 存储和查找的时间复杂度可达到O(1) |
内存占用 | 内存使用较少 | 以空间换时间,内存占用较高 |
简而言之,在需要有序性或者对单次查询有时间要求的应用场景下,应使用map,其余情况应使用unordered_map。
可参考:map与unordered_map的性能对比
回到题目中,这两种容器恰好都是我们需要的:
1.我们需要用到红黑树来记录价格,键值对为<price, count>。count表示价格为price的时间戳的数量(如果数量为0,就从map中删除该节点)。map会在插入和删除键值对的过程中进行自动排序,我们直接从map的头部和尾部分别取得最小值和最大值即可。
2.还需要用哈希表记录某一时间戳的股票价格,键值对为<time, price>。输入一条新记录时,如果时间戳已存在,需要通过哈希表查找之前的价格oldPrice,将红黑树上oldPrice对应的count减去1,再插入新的price。
代码
class StockPrice {
private:
// 记录某一时间戳的股票价格的哈希表.键值对为<time, price>
unordered_map<int, int> hashMap;
// 记录某一价格及其对应的时间戳的数量的红黑树.键值对为<price, count>(对key值从小到大进行自动排序)
map<int, int> treeMap;
int curPrice;
int curTimestamp;
public:
StockPrice() {
curTimestamp = 0;
}
void update(int timestamp, int price) {
// 更新最新股票价格
if (timestamp >= curTimestamp){
curPrice = price;
curTimestamp = timestamp;
}
// 更新红黑树
if (hashMap.count(timestamp)){
// 若时间戳已存在
// 找到该时间戳原本对应的价格并移除
int oldPrice = hashMap[timestamp];
if(--treeMap[oldPrice] == 0)
treeMap.erase(oldPrice);
}
hashMap[timestamp] = price;
treeMap[price] += 1;
}
int current() {
return curPrice;
}
int maximum() {
return treeMap.rbegin() -> first;
}
int minimum() {
return treeMap.begin() -> first;
}
};
/**
* Your StockPrice object will be instantiated and called as such:
* StockPrice* obj = new StockPrice();
* obj->update(timestamp,price);
* int param_2 = obj->current();
* int param_3 = obj->maximum();
* int param_4 = obj->minimum();
*/