2034. 股票价格波动
给你一支股票价格的数据流。数据流中每一条记录包含一个 时间戳 和该时间点股票对应的 价格 。
不巧的是,由于股票市场内在的波动性,股票价格记录可能不是按时间顺序到来的。某些情况下,有的记录可能是错的。如果两个有相同时间戳的记录出现在数据流中,前一条记录视为错误记录,后出现的记录 更正 前一条错误的记录。
请你设计一个算法,实现:
请你实现 StockPrice
类:
StockPrice()
初始化对象,当前无股票价格记录。void update(int timestamp, int price)
在时间点 timestamp
更新股票价格为 price
。int current()
返回股票 最新价格 。int maximum()
返回股票 最高价格 。int minimum()
返回股票 最低价格 。
示例 1:
输入: ["StockPrice", "update", "update", "current", "maximum", "update", "maximum", "update", "minimum"] [[], [1, 10], [2, 5], [], [], [1, 3], [], [4, 2], []] 输出: [null, null, null, 5, 10, null, 5, null, 2] 解释: StockPrice stockPrice = new StockPrice(); stockPrice.update(1, 10); // 时间戳为 [1] ,对应的股票价格为 [10] 。 stockPrice.update(2, 5); // 时间戳为 [1,2] ,对应的股票价格为 [10,5] 。 stockPrice.current(); // 返回 5 ,最新时间戳为 2 ,对应价格为 5 。 stockPrice.maximum(); // 返回 10 ,最高价格的时间戳为 1 ,价格为 10 。 stockPrice.update(1, 3); // 之前时间戳为 1 的价格错误,价格更新为 3 。 // 时间戳为 [1,2] ,对应股票价格为 [3,5] 。 stockPrice.maximum(); // 返回 5 ,更正后最高价格为 5 。 stockPrice.update(4, 2); // 时间戳为 [1,2,4] ,对应价格为 [3,5,2] 。 stockPrice.minimum(); // 返回 2 ,最低价格时间戳为 4 ,价格为 2 。
提示:
1 <= timestamp, price <= 109
update
,current
,maximum
和 minimum
总 调用次数不超过 105
。current
,maximum
和 minimum
被调用时,update
操作 至少 已经被调用过 一次 。原站题解
cpp 解法, 执行用时: 376 ms, 内存消耗: 158.9 MB, 提交时间: 2023-10-08 07:34:04
typedef pair<int,int> pii; class StockPrice { public: StockPrice() { this->maxTimestamp = 0; } void update(int timestamp, int price) { maxTimestamp = max(maxTimestamp, timestamp); timePriceMap[timestamp] = price; pqMax.emplace(price, timestamp); pqMin.emplace(price, timestamp); } int current() { return timePriceMap[maxTimestamp]; } int maximum() { while (true) { int price = pqMax.top().first, timestamp = pqMax.top().second; if (timePriceMap[timestamp] == price) { return price; } pqMax.pop(); } } int minimum() { while (true) { int price = pqMin.top().first, timestamp = pqMin.top().second; if (timePriceMap[timestamp] == price) { return price; } pqMin.pop(); } } private: int maxTimestamp; unordered_map<int, int> timePriceMap; priority_queue<pii, vector<pii>, less<pii>> pqMax; priority_queue<pii, vector<pii>, greater<pii>> pqMin; }; /** * 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(); */
cpp 解法, 执行用时: 420 ms, 内存消耗: 163.7 MB, 提交时间: 2023-10-08 07:33:41
class StockPrice { public: StockPrice() { this->maxTimestamp = 0; } void update(int timestamp, int price) { maxTimestamp = max(maxTimestamp, timestamp); int prevPrice = timePriceMap.count(timestamp) ? timePriceMap[timestamp] : 0; timePriceMap[timestamp] = price; if (prevPrice > 0) { auto it = prices.find(prevPrice); if (it != prices.end()) { prices.erase(it); } } prices.emplace(price); } int current() { return timePriceMap[maxTimestamp]; } int maximum() { return *prices.rbegin(); } int minimum() { return *prices.begin(); } private: int maxTimestamp; unordered_map<int, int> timePriceMap; multiset<int> prices; }; /** * 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(); */
javascript 解法, 执行用时: 516 ms, 内存消耗: 87 MB, 提交时间: 2023-10-08 07:32:46
var StockPrice = function() { this.map = new Map(); this.obj = { time: -1, price: -1 }; // 可以整体排序,避免每一次都需要排序 this.maxQueue = new MaxPriorityQueue({ compare: (e1,e2) => e2.price - e1.price }); this.minQueue = new MinPriorityQueue({ compare: (e1,e2) => e1.price - e2.price }); }; /** * @param {number} timestamp * @param {number} price * @return {void} */ StockPrice.prototype.update = function(timestamp, price) { this.map.set(timestamp, price); this.maxQueue.enqueue({ time: timestamp, price: price }); this.minQueue.enqueue({ time: timestamp, price: price }); if(this.obj.time <= timestamp) { this.obj.price = price this.obj.time = timestamp } }; /** * @return {number} */ StockPrice.prototype.current = function() { return this.obj.price; }; /** * @return {number} */ StockPrice.prototype.maximum = function() { // 判断当前的是否是正确的 while(true) { let cur = this.maxQueue.front(), t = this.map.get(cur.time); if(cur.price === t) { return cur.price; }else this.maxQueue.dequeue(); } }; /** * @return {number} */ StockPrice.prototype.minimum = function() { while(true) { let cur = this.minQueue.front(), t = this.map.get(cur.time); if(cur.price === t) { return cur.price; }else this.minQueue.dequeue(); } }; /** * Your StockPrice object will be instantiated and called as such: * var obj = new StockPrice() * obj.update(timestamp,price) * var param_2 = obj.current() * var param_3 = obj.maximum() * var param_4 = obj.minimum() */
rust 解法, 执行用时: 112 ms, 内存消耗: 41.6 MB, 提交时间: 2023-10-08 07:30:23
use std::collections::{BTreeMap, HashMap, HashSet}; struct StockPrice { time_tab: HashMap<i32, i32>, cur_time: i32, cur_price: i32, price_tab: BTreeMap<i32, HashSet<i32>> } /** * `&self` means the method takes an immutable reference. * If you need a mutable reference, change it to `&mut self` instead. */ impl StockPrice { fn new() -> Self { Self { time_tab: HashMap::with_capacity(10000), cur_time: 0, cur_price: 0, price_tab: BTreeMap::new(), } } fn update(&mut self, timestamp: i32, price: i32) { if timestamp >= self.cur_time { self.cur_time = timestamp; self.cur_price = price; } if let Some(p) = self.time_tab.get_mut(×tamp) { let old_price = *p; *p = price; let t = self.price_tab.get_mut(&old_price).unwrap(); t.remove(×tamp); if t.is_empty() { self.price_tab.remove(&old_price); } let t = self.price_tab.entry(price).or_insert(HashSet::new()); t.insert(timestamp); } else { self.time_tab.insert(timestamp, price); let t = self.price_tab.entry(price).or_insert(HashSet::new()); t.insert(timestamp); } } fn current(&self) -> i32 { self.cur_price } fn maximum(&self) -> i32 { *self.price_tab.iter().rev().next().unwrap().0 } fn minimum(&self) -> i32 { *self.price_tab.iter().next().unwrap().0 } } /** * Your StockPrice object will be instantiated and called as such: * let obj = StockPrice::new(); * obj.update(timestamp, price); * let ret_2: i32 = obj.current(); * let ret_3: i32 = obj.maximum(); * let ret_4: i32 = obj.minimum(); */
python3 解法, 执行用时: 504 ms, 内存消耗: 64.3 MB, 提交时间: 2023-06-25 09:53:32
class StockPrice: def __init__(self): self.maxPrice = [] self.minPrice = [] self.timePriceMap = {} self.maxTimestamp = 0 def update(self, timestamp: int, price: int) -> None: heappush(self.maxPrice, (-price, timestamp)) heappush(self.minPrice, (price, timestamp)) self.timePriceMap[timestamp] = price self.maxTimestamp = max(self.maxTimestamp, timestamp) def current(self) -> int: return self.timePriceMap[self.maxTimestamp] def maximum(self) -> int: while True: price, timestamp = self.maxPrice[0] if -price == self.timePriceMap[timestamp]: return -price heappop(self.maxPrice) def minimum(self) -> int: while True: price, timestamp = self.minPrice[0] if price == self.timePriceMap[timestamp]: return price heappop(self.minPrice) # Your StockPrice object will be instantiated and called as such: # obj = StockPrice() # obj.update(timestamp,price) # param_2 = obj.current() # param_3 = obj.maximum() # param_4 = obj.minimum()
golang 解法, 执行用时: 500 ms, 内存消耗: 41.2 MB, 提交时间: 2023-06-25 09:52:49
type StockPrice struct { prices *redblacktree.Tree timePriceMap map[int]int maxTimestamp int } func Constructor() StockPrice { return StockPrice{redblacktree.NewWithIntComparator(), map[int]int{}, 0} } func (sp *StockPrice) Update(timestamp, price int) { if prevPrice := sp.timePriceMap[timestamp]; prevPrice > 0 { if times, _ := sp.prices.Get(prevPrice); times.(int) > 1 { sp.prices.Put(prevPrice, times.(int)-1) } else { sp.prices.Remove(prevPrice) } } times := 0 if val, ok := sp.prices.Get(price); ok { times = val.(int) } sp.prices.Put(price, times+1) sp.timePriceMap[timestamp] = price if timestamp >= sp.maxTimestamp { sp.maxTimestamp = timestamp } } func (sp *StockPrice) Current() int { return sp.timePriceMap[sp.maxTimestamp] } func (sp *StockPrice) Maximum() int { return sp.prices.Right().Key.(int) } func (sp *StockPrice) Minimum() int { return sp.prices.Left().Key.(int) } /** * Your StockPrice object will be instantiated and called as such: * obj := Constructor(); * obj.Update(timestamp,price); * param_2 := obj.Current(); * param_3 := obj.Maximum(); * param_4 := obj.Minimum(); */
java 解法, 执行用时: 109 ms, 内存消耗: 102.5 MB, 提交时间: 2023-06-25 09:52:12
class StockPrice { private int maxTime; private Map<Integer, Integer> timeMap; private TreeMap<Integer, Integer> priceMap; public StockPrice() { maxTime = 0; timeMap = new HashMap<>(); priceMap = new TreeMap<>(); } public void update(int timestamp, int price) { if(timeMap.containsKey(timestamp)){ int oldPrice = timeMap.get(timestamp); int cnt = priceMap.get(oldPrice); if(cnt == 1) priceMap.remove(oldPrice); else priceMap.put(oldPrice, cnt - 1); } timeMap.put(timestamp, price); priceMap.put(price, priceMap.getOrDefault(price, 0) + 1); maxTime = Math.max(maxTime, timestamp); } public int current() { return timeMap.get(maxTime); } public int maximum() { return priceMap.lastKey(); } public int minimum() { return priceMap.firstKey(); } } /** * 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(); */
golang 解法, 执行用时: 488 ms, 内存消耗: 41.9 MB, 提交时间: 2023-06-25 09:51:48
type StockPrice struct { maxTime int timeMap map[int]int maxPrice, minPrice IntHeap } func Constructor() StockPrice { return StockPrice{timeMap:map[int]int{}} } func (this *StockPrice) Update(timestamp int, price int) { if this.maxTime < timestamp { this.maxTime = timestamp } this.timeMap[timestamp] = price heap.Push(&this.maxPrice, []int{-price, timestamp}) heap.Push(&this.minPrice, []int{price, timestamp}) } func (this *StockPrice) Current() int { return this.timeMap[this.maxTime] } func (this *StockPrice) Maximum() int { for { cur := heap.Pop(&this.maxPrice).([]int) v := this.timeMap[cur[1]] if v == -cur[0] { heap.Push(&this.maxPrice, cur) return v } } } func (this *StockPrice) Minimum() int { for { cur := heap.Pop(&this.minPrice).([]int) v := this.timeMap[cur[1]] if v == cur[0] { heap.Push(&this.minPrice, cur) return v } } } /** * Your StockPrice object will be instantiated and called as such: * obj := Constructor(); * obj.Update(timestamp,price); * param_2 := obj.Current(); * param_3 := obj.Maximum(); * param_4 := obj.Minimum(); */ type IntHeap [][]int func (h IntHeap) Len() int{return len(h)} func (h IntHeap) Less(i, j int) bool{return h[i][0] < h[j][0]} func (h IntHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i]} func (h *IntHeap) Pop() interface{} { old := *h n := len(old) x := old[n - 1] *h = old[0 : n - 1] return x } func (h *IntHeap) Push(x interface{}) { *h = append(*h, x.([]int)) }
python3 解法, 执行用时: 652 ms, 内存消耗: 55.7 MB, 提交时间: 2023-06-25 09:51:12
''' 模拟 维护一个最大的时间戳,维护一个价格的有序列表(在相同时间戳更新价格时删掉原来错误的时间戳) ''' from sortedcontainers import SortedList class StockPrice: def __init__(self): self.sl = SortedList() self.time_map = {} self.max_time = -inf def update(self, timestamp: int, price: int) -> None: if timestamp in self.time_map: self.sl.discard(self.time_map[timestamp]) self.sl.add(price) self.time_map[timestamp] = price self.max_time = max(self.max_time, timestamp) def current(self) -> int: return self.time_map[self.max_time] def maximum(self) -> int: return self.sl[-1] def minimum(self) -> int: return self.sl[0] # Your StockPrice object will be instantiated and called as such: # obj = StockPrice() # obj.update(timestamp,price) # param_2 = obj.current() # param_3 = obj.maximum() # param_4 = obj.minimum()