|
| 1 | +--- |
| 2 | +title: 2034.股票价格波动 |
| 3 | +date: 2023-10-08 12:36:36 |
| 4 | +tags: [题解, LeetCode, 中等, 设计, 哈希表, 数据流, 有序集合, 堆(优先队列), set, map] |
| 5 | +--- |
| 6 | + |
| 7 | +# 【LetMeFly】2034.股票价格波动:哈希表 + 有序集合 |
| 8 | + |
| 9 | +力扣题目链接:[https://leetcode.cn/problems/stock-price-fluctuation/](https://leetcode.cn/problems/stock-price-fluctuation/) |
| 10 | + |
| 11 | +<p>给你一支股票价格的数据流。数据流中每一条记录包含一个 <strong>时间戳</strong> 和该时间点股票对应的 <strong>价格</strong> 。</p> |
| 12 | + |
| 13 | +<p>不巧的是,由于股票市场内在的波动性,股票价格记录可能不是按时间顺序到来的。某些情况下,有的记录可能是错的。如果两个有相同时间戳的记录出现在数据流中,前一条记录视为错误记录,后出现的记录 <b>更正</b> 前一条错误的记录。</p> |
| 14 | + |
| 15 | +<p>请你设计一个算法,实现:</p> |
| 16 | + |
| 17 | +<ul> |
| 18 | + <li><strong>更新 </strong>股票在某一时间戳的股票价格,如果有之前同一时间戳的价格,这一操作将 <strong>更正</strong> 之前的错误价格。</li> |
| 19 | + <li>找到当前记录里 <b>最新股票价格</b> 。<strong>最新股票价格</strong> 定义为时间戳最晚的股票价格。</li> |
| 20 | + <li>找到当前记录里股票的 <strong>最高价格</strong> 。</li> |
| 21 | + <li>找到当前记录里股票的 <strong>最低价格</strong> 。</li> |
| 22 | +</ul> |
| 23 | + |
| 24 | +<p>请你实现 <code>StockPrice</code> 类:</p> |
| 25 | + |
| 26 | +<ul> |
| 27 | + <li><code>StockPrice()</code> 初始化对象,当前无股票价格记录。</li> |
| 28 | + <li><code>void update(int timestamp, int price)</code> 在时间点 <code>timestamp</code> 更新股票价格为 <code>price</code> 。</li> |
| 29 | + <li><code>int current()</code> 返回股票 <strong>最新价格</strong> 。</li> |
| 30 | + <li><code>int maximum()</code> 返回股票 <strong>最高价格</strong> 。</li> |
| 31 | + <li><code>int minimum()</code> 返回股票 <strong>最低价格</strong> 。</li> |
| 32 | +</ul> |
| 33 | + |
| 34 | +<p> </p> |
| 35 | + |
| 36 | +<p><strong>示例 1:</strong></p> |
| 37 | + |
| 38 | +<pre><strong>输入:</strong> |
| 39 | +["StockPrice", "update", "update", "current", "maximum", "update", "maximum", "update", "minimum"] |
| 40 | +[[], [1, 10], [2, 5], [], [], [1, 3], [], [4, 2], []] |
| 41 | +<strong>输出:</strong> |
| 42 | +[null, null, null, 5, 10, null, 5, null, 2] |
| 43 | + |
| 44 | +<strong>解释:</strong> |
| 45 | +StockPrice stockPrice = new StockPrice(); |
| 46 | +stockPrice.update(1, 10); // 时间戳为 [1] ,对应的股票价格为 [10] 。 |
| 47 | +stockPrice.update(2, 5); // 时间戳为 [1,2] ,对应的股票价格为 [10,5] 。 |
| 48 | +stockPrice.current(); // 返回 5 ,最新时间戳为 2 ,对应价格为 5 。 |
| 49 | +stockPrice.maximum(); // 返回 10 ,最高价格的时间戳为 1 ,价格为 10 。 |
| 50 | +stockPrice.update(1, 3); // 之前时间戳为 1 的价格错误,价格更新为 3 。 |
| 51 | + // 时间戳为 [1,2] ,对应股票价格为 [3,5] 。 |
| 52 | +stockPrice.maximum(); // 返回 5 ,更正后最高价格为 5 。 |
| 53 | +stockPrice.update(4, 2); // 时间戳为 [1,2,4] ,对应价格为 [3,5,2] 。 |
| 54 | +stockPrice.minimum(); // 返回 2 ,最低价格时间戳为 4 ,价格为 2 。 |
| 55 | +</pre> |
| 56 | + |
| 57 | +<p> </p> |
| 58 | + |
| 59 | +<p><strong>提示:</strong></p> |
| 60 | + |
| 61 | +<ul> |
| 62 | + <li><code>1 <= timestamp, price <= 10<sup>9</sup></code></li> |
| 63 | + <li><code>update</code>,<code>current</code>,<code>maximum</code> 和 <code>minimum</code> <strong>总</strong> 调用次数不超过 <code>10<sup>5</sup></code> 。</li> |
| 64 | + <li><code>current</code>,<code>maximum</code> 和 <code>minimum</code> 被调用时,<code>update</code> 操作 <strong>至少</strong> 已经被调用过 <strong>一次</strong> 。</li> |
| 65 | +</ul> |
| 66 | + |
| 67 | + |
| 68 | + |
| 69 | +## 方法一:哈希表 + 有序集合 |
| 70 | + |
| 71 | +只需要维护三个变量: |
| 72 | + |
| 73 | ++ 哈希表```ma```用来将```时间戳```映射为```价格``` |
| 74 | ++ 有序集合```se```(例如C++的multiset)用来存储所有的股票价格 |
| 75 | ++ 整数```Mtime```用来存最新的时间戳 |
| 76 | + |
| 77 | +那么: |
| 78 | + |
| 79 | ++ 对于```update```操作,如果哈希表```ma```中已经存在了这个时间戳,就删除有序集合```se```中这个时间戳对应的价格。然后更新```ma```、```se```和```Mtime``` |
| 80 | ++ 对于```current```操作,直接返回哈希表```ma```中最新时间戳```Mtime```对应的价格 |
| 81 | ++ 对于```maximum```操作,直接返回有序集合```se```中的最后一个元素 |
| 82 | ++ 对于```minimum```操作,直接返回有序集合```se```中的第一个元素 |
| 83 | + |
| 84 | +完毕。 |
| 85 | + |
| 86 | ++ 时间复杂度:单次操作涉及有序集合增删的复杂的为$O(\log n)$,否则复杂度为$O(1)$ |
| 87 | ++ 空间复杂度:$O(n)$,其中$n$是不用的时间戳数量 |
| 88 | + |
| 89 | +### AC代码 |
| 90 | + |
| 91 | +#### C++ |
| 92 | + |
| 93 | +```cpp |
| 94 | +class StockPrice { |
| 95 | +private: |
| 96 | + unordered_map<int, int> ma; |
| 97 | + multiset<int> se; |
| 98 | + int Mtime; |
| 99 | +public: |
| 100 | + StockPrice() { |
| 101 | + Mtime = 0; |
| 102 | + } |
| 103 | + |
| 104 | + void update(int timestamp, int price) { |
| 105 | + if (ma.count(timestamp)) { |
| 106 | + se.erase(se.find(ma[timestamp])); |
| 107 | + } |
| 108 | + ma[timestamp] = price; |
| 109 | + se.insert(price); |
| 110 | + Mtime = max(Mtime, timestamp); |
| 111 | + } |
| 112 | + |
| 113 | + int current() { |
| 114 | + return ma[Mtime]; |
| 115 | + } |
| 116 | + |
| 117 | + int maximum() { |
| 118 | + return *se.rbegin(); |
| 119 | + } |
| 120 | + |
| 121 | + int minimum() { |
| 122 | + return *se.begin(); |
| 123 | + } |
| 124 | +}; |
| 125 | +``` |
| 126 | +
|
| 127 | +#### Python |
| 128 | +
|
| 129 | +```python |
| 130 | +# from sortedcontainers import SortedList |
| 131 | +
|
| 132 | +
|
| 133 | +class StockPrice: |
| 134 | +
|
| 135 | + def __init__(self): |
| 136 | + self.ma = {} |
| 137 | + self.se = SortedList() |
| 138 | + self.Mtime = 0 |
| 139 | +
|
| 140 | +
|
| 141 | + def update(self, timestamp: int, price: int) -> None: |
| 142 | + if timestamp in self.ma: |
| 143 | + self.se.discard(self.ma[timestamp]) |
| 144 | + self.ma[timestamp] = price |
| 145 | + self.se.add(price) |
| 146 | + self.Mtime = max(self.Mtime, timestamp) |
| 147 | +
|
| 148 | +
|
| 149 | + def current(self) -> int: |
| 150 | + return self.ma[self.Mtime] |
| 151 | +
|
| 152 | +
|
| 153 | + def maximum(self) -> int: |
| 154 | + return self.se[-1] |
| 155 | +
|
| 156 | +
|
| 157 | + def minimum(self) -> int: |
| 158 | + return self.se[0] |
| 159 | +
|
| 160 | +``` |
| 161 | + |
| 162 | +> 同步发文于CSDN,原创不易,转载经作者同意后请附上[原文链接](https://blog.tisfy.eu.org/2023/10/08/LeetCode%202034.%E8%82%A1%E7%A5%A8%E4%BB%B7%E6%A0%BC%E6%B3%A2%E5%8A%A8/)哦~ |
| 163 | +> Tisfy:[https://letmefly.blog.csdn.net/article/details/133677649](https://letmefly.blog.csdn.net/article/details/133677649) |
0 commit comments