题目:创建一个基于时间的键值存储类 TimeMap,它支持下面两个操作:
- set(string key, string value, int timestamp)
存储键 key、值 value,以及给定的时间戳 timestamp。 - get(string key, int timestamp)
返回先前调用 set(key, value, timestamp_prev) 所存储的值,其中 timestamp_prev <= timestamp。
如果有多个这样的值,则返回对应最大的 timestamp_prev 的那个值。
如果没有值,则返回空字符串("")。
注:
- 所有的键/值字符串都是小写的。
- 所有的键/值字符串长度都在 [1, 100] 范围内。
- 所有 TimeMap.set 操作中的时间戳timestamps 都是严格递增的。
- 1 <= timestamp <= 10^7
- TimeMap.set 和 TimeMap.get函数在每个测试用例中将(组合)调用总计 120000 次。
题解:
class TimeMap {
//内部类
class Pair implements Comparable<Pair> {
int timestamp; //时间戳
String value; //值
public Pair(int timestamp, String value) {
this.timestamp = timestamp;
this.value = value;
}
public int hashCode() {
return timestamp + value.hashCode();
}
public boolean equals(Object obj) {
if (obj instanceof Pair) {
Pair pair2 = (Pair) obj;
return this.timestamp == pair2.timestamp && this.value.equals(pair2.value);
}
return false;
}
public int compareTo(Pair pair2) {
if (this.timestamp != pair2.timestamp) {
return this.timestamp - pair2.timestamp;
} else {
return this.value.compareTo(pair2.value);
}
}
}
//为实现get 操作,用一个哈希表存储set 操作传入的数据
//哈希表的键为字符串key,值为一个二元组列表,二元组中存储的是时间戳timestamp 和值value。
Map<String, List<Pair>> map;
public TimeMap() {
map = new HashMap<String, List<Pair>>();
}
public void set(String key, String value, int timestamp) {
List<Pair> pairs = map.getOrDefault(key, new ArrayList<Pair>());
pairs.add(new Pair(timestamp, value));
map.put(key, pairs);
}
public String get(String key, int timestamp) {
List<Pair> pairs = map.getOrDefault(key, new ArrayList<Pair>());
// 使用一个大于所有 value 的字符串,以确保在 pairs 中含有 timestamp 的情况下也返回大于 timestamp 的位置
Pair pair = new Pair(timestamp, String.valueOf((char) 127));
int i = binarySearch(pairs, pair);
if (i > 0) {
return pairs.get(i - 1).value;
}
return "";
}
private int binarySearch(List<Pair> pairs, Pair target) {
int low = 0, high = pairs.size() - 1;
if (high < 0 || pairs.get(high).compareTo(target) <= 0) {
return high + 1;
}
while (low < high) {
int mid = (high - low) / 2 + low;
Pair pair = pairs.get(mid);
if (pair.compareTo(target) <= 0) {
low = mid + 1;
} else {
high = mid;
}
}
return low;
}
}
复杂度分析
- 时间复杂度: 初始化 TimeMap 和 set 操作均为O(1); get 操作为 O(logn),其中 n 是set
操作的次数。最坏情况下set 操作插入的 key 均相同,这种情况下get 中二分查找的次数为 O(logn)。 - **空间复杂度:**O(n),其中 n 是set 操作的次数。我们需要使用哈希表保存每一次set 操作的信息。
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/time-based-key-value-store/solution/ji-yu-shi-jian-de-jian-zhi-cun-chu-by-le-t98o/
来源:力扣(LeetCode)