题目描述
设计一个基于时间的键值数据结构,该结构可以在不同时间戳存储对应同一个键的多个值,并针对特定时间戳检索键对应的值。
实现 TimeMap
类:
TimeMap()
初始化数据结构对象void set(String key, String value, int timestamp)
存储键key
、值value
,以及给定的时间戳timestamp
。String get(String key, int timestamp)
- 返回之前调用
set(key, value, timestamp_prev)
所存储的值,其中timestamp_prev <= timestamp
。 - 如果有多个这样的值,则返回对应最大的
timestamp_prev
的那个值。 - 如果没有值,则返回空字符串(
""
)。
- 返回之前调用
样例
输入:
["TimeMap", "set", "get", "get", "set", "get", "get"]
[[],
["foo", "bar", 1], ["foo", 1], ["foo", 3],
["foo", "bar2", 4], ["foo", 4], ["foo", 5]
]
输出:
[null, null, "bar", "bar", null, "bar2", "bar2"]
解释:
TimeMap timeMap = new TimeMap();
timeMap.set("foo", "bar", 1);
// 存储键 "foo" 和值 "bar" ,时间戳 timestamp = 1
timeMap.get("foo", 1);
// 返回 "bar"
timeMap.get("foo", 3);
// 返回 "bar", 因为在时间戳 3 和时间戳 2 处没有对应 "foo" 的值,
所以唯一的值位于时间戳 1 处(即 "bar")。
timeMap.set("foo", "bar2", 4);
// 存储键 "foo" 和值 "bar2",时间戳 timestamp = 4
timeMap.get("foo", 4);
// 返回 "bar2"
timeMap.get("foo", 5);
// 返回 "bar2"
限制
1 <= key.length, value.length <= 100
key
和value
由小写英文字母和数字组成。1 <= timestamp <= 10^7
set
操作中的时间戳timestamp
都是严格递增的。- 最多调用
set
和get
操作2 * 10^5
次。
算法
(哈希表) 单次查询 $O(\log n)$
- 设计一个哈希表,存储
key
到二元组数组,其中每个二元组都是(timestamp, value)
。 - 对于插入操作,直接在对应的键值中,添加对应的时间戳和值。
- 对于查询操作,如果不存在该
key
或者key
对应的数组为空,或者待查询的时间戳比数组中最小的时间戳还要小,则返回空字符串。 - 其他情况,在二元组数组中二分,找到最大的小于等于当前查询时间戳的位置,并返回其值。
时间复杂度
- 对于插入操作,直接找到对应位置插入一个值,时间复杂度为常数。
- 对于查询操作,获取到对应键的数组后,需要二分查询,故时间复杂度为 $O(\log n)$。其中 $n$ 为插入操作的总次数。
空间复杂度
- 需要 $O(n)$ 的额外空间存储哈希表。
C++ 代码
class TimeMap {
private:
unordered_map<string, vector<pair<int, string>>> h;
public:
/** Initialize your data structure here. */
TimeMap() {
}
void set(string key, string value, int timestamp) {
h[key].emplace_back(timestamp, value);
}
string get(string key, int timestamp) {
if (h.find(key) == h.end())
return "";
const vector<pair<int, string>> &hk = h[key];
if (hk.empty() || hk[0].first > timestamp)
return "";
int l = 0, r = hk.size() - 1;
while (l < r) {
int mid = (l + r) >> 1;
if (hk[mid + 1].first <= timestamp) l = mid + 1;
else r = mid;
}
return hk[l].second;
}
};
/**
* Your TimeMap object will be instantiated and called as such:
* TimeMap* obj = new TimeMap();
* obj->set(key,value,timestamp);
* string param_2 = obj->get(key,timestamp);
*/
这里只需要一个hashmap应该就可以,因为set 操作中的时间戳 timestamp 都是严格递增的,可以把map的value定义成pair的形式。
代码已更新