Medium

题目描述

给你一股票价格的数据流。每条记录包含一个 时间戳 和该时间戳对应的股票 价格

不巧的是,由于股票市场内在的波动性,股票价格记录可能不是按时间顺序到来的。某些情况下,有些记录可能是错的。如果两个有相同时间戳的记录出现在数据流中,前一条记录视为错误记录,后出现的记录 更正 前一条错误的记录。

请你设计一个算法,实现:

  • 更新 股票在某一时间戳的股票价格,如果有之前同一时间戳的价格,这一操作将 更正 之前的错误价格。
  • 找到当前记录里 最新股票价格最新股票价格 定义为时间戳最晚的股票价格。
  • 找到当前记录里股票的 最高价格
  • 找到当前记录里股票的 最低价格

请你实现 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 <= 10^9
  • updatecurrentmaximumminimum调用次数 不超过 10^5
  • currentmaximumminimum 被调用时,update 操作 至少 已经被调用过 一次

解题思路

这道题需要我们设计一个数据结构来处理股票价格的动态更新和查询操作。

核心难点在于需要同时支持:

  1. 根据时间戳更新价格(可能覆盖之前的错误记录)
  2. 快速查询最新价格(最大时间戳对应的价格)
  3. 快速查询最高价格和最低价格

解决方案: 我们使用**哈希表 + 有序集合(或堆)**的组合:

  1. 哈希表 timestamp_to_price:存储时间戳到价格的映射,用于快速更新和查询特定时间戳的价格
  2. 变量 latest_timestamp:记录当前最大的时间戳,用于快速返回最新价格
  3. 有序集合 prices:维护所有当前有效的价格,支持快速查询最大值和最小值

更新操作的处理

  • 如果是新的时间戳,直接添加到哈希表和有序集合中
  • 如果是已存在的时间戳,需要先从有序集合中删除旧价格,再添加新价格

时间复杂度:使用有序集合(如 C++ 的 multiset)可以保证所有操作都是 O(log n) 的复杂度。

代码实现

class StockPrice {
private:
    unordered_map<int, int> timestamp_to_price;
    multiset<int> prices;
    int latest_timestamp;
    
public:
    StockPrice() {
        latest_timestamp = 0;
    }
    
    void update(int timestamp, int price) {
        if (timestamp_to_price.count(timestamp)) {
            int old_price = timestamp_to_price[timestamp];
            prices.erase(prices.find(old_price));
        }
        
        timestamp_to_price[timestamp] = price;
        prices.insert(price);
        latest_timestamp = max(latest_timestamp, timestamp);
    }
    
    int current() {
        return timestamp_to_price[latest_timestamp];
    }
    
    int maximum() {
        return *prices.rbegin();
    }
    
    int minimum() {
        return *prices.begin();
    }
};
from sortedcontainers import SortedList

class StockPrice:
    def __init__(self):
        self.timestamp_to_price = {}
        self.prices = SortedList()
        self.latest_timestamp = 0

    def update(self, timestamp: int, price: int) -> None:
        if timestamp in self.timestamp_to_price:
            old_price = self.timestamp_to_price[timestamp]
            self.prices.remove(old_price)
        
        self.timestamp_to_price[timestamp] = price
        self.prices.add(price)
        self.latest_timestamp = max(self.latest_timestamp, timestamp)

    def current(self) -> int:
        return self.timestamp_to_price[self.latest_timestamp]

    def maximum(self) -> int:
        return self.prices[-1]

    def minimum(self) -> int:
        return self.prices[0]
public class StockPrice {
    private Dictionary<int, int> timestampToPrice;
    private SortedDictionary<int, int> priceCount;
    private int latestTimestamp;

    public StockPrice() {
        timestampToPrice = new Dictionary<int, int>();
        priceCount = new SortedDictionary<int, int>();
        latestTimestamp = 0;
    }
    
    public void Update(int timestamp, int price) {
        if (timestampToPrice.ContainsKey(timestamp)) {
            int oldPrice = timestampToPrice[timestamp];
            priceCount[oldPrice]--;
            if (priceCount[oldPrice] == 0) {
                priceCount.Remove(oldPrice);
            }
        }
        
        timestampToPrice[timestamp] = price;
        if (!priceCount.ContainsKey(price)) {
            priceCount[price] = 0;
        }
        priceCount[price]++;
        latestTimestamp = Math.Max(latestTimestamp, timestamp);
    }
    
    public int Current() {
        return timestampToPrice[latestTimestamp];
    }
    
    public int Maximum() {
        return priceCount.Keys.Last();
    }
    
    public int Minimum() {
        return priceCount.Keys.First();
    }
}
var StockPrice = function() {
    this.timestampToPrice = new Map();
    this.prices = [];
    this.latestTimestamp = 0;
};

StockPrice.prototype.update = function(timestamp, price) {
    if (this.timestampToPrice.has(timestamp)) {
        const oldPrice = this.timestampToPrice.get(timestamp);
        const index = this.prices.indexOf(oldPrice);
        this.prices.splice(index, 1);
    }
    
    this.timestampToPrice.set(timestamp, price);
    this.prices.push(price);
    this.prices.sort((a, b) => a - b);
    this.latestTimestamp = Math.max(this.latestTimestamp, timestamp);
};

StockPrice.prototype.current = function() {
    return this.timestampToPrice.get(this.latestTimestamp);
};

StockPrice.prototype.maximum = function() {
    return this.prices[this.prices.length - 1];
};

StockPrice.prototype.minimum = function() {
    return this.prices[0];
};

复杂度分析

操作时间复杂度空间复杂度
updateO(log n)O(n)
currentO(1)O(1)
maximumO(1)O(1)
minimumO(1)O(1)

说明

  • n 为不同价格的数量
  • 使用有序集合(multiset/SortedList)保证了最优的时间复杂度
  • 空间复杂度主要来自存储时间戳-价格映射和价格的有序集合

相关题目