Repository navigation
Expand file tree
/
Copy pathLC981.cpp
More file actions
131 lines (102 loc) · 4.15 KB
/
Copy pathLC981.cpp
File metadata and controls
131 lines (102 loc) · 4.15 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/*
Question: Time Based Key-Value Store
Design a data structure that stores multiple values for each key at different timestamps.
Implement:
- set(key, value, timestamp): Store the value for the key at the given timestamp.
- get(key, timestamp): Return the value with the largest stored timestamp ≤ the requested timestamp. Return "" if no qualifying value exists.
Assumption: Timestamps supplied to set() are strictly increasing, as required by LeetCode 981.
Solution
Use an unordered_map to associate each key with a sorted vector of timestamped values. Append during set(), and binary-search during get().
The following complete C++20 program includes a driver with test cases:
g++ -std=c++20 -Wall -Wextra -pedantic time_map.cpp -o time_map
./time_map
*/
#include <iostream>
#include <string>
#include <unordered_map>
#include <vector>
class TimeMap {
struct Record {
int timestamp;
std::string value;
};
std::unordered_map<std::string, std::vector<Record>> history_;
public:
void set(const std::string& key,
const std::string& value,
int timestamp) {
history_[key].push_back({timestamp, value});
}
std::string get(const std::string& key, int timestamp) const {
const auto it = history_.find(key);
if (it == history_.end()) {
return "";
}
const auto& records = it->second;
// Search the half-open range [left, right).
std::size_t left = 0;
std::size_t right = records.size();
// Find the first record whose timestamp exceeds the query.
while (left < right) {
const auto middle = left + (right - left) / 2;
if (records[middle].timestamp <= timestamp) {
left = middle + 1;
} else {
right = middle;
}
}
// No timestamp was <= the query.
if (left == 0) {
return "";
}
return records[left - 1].value;
}
};
int main() {
TimeMap store;
int passed = 0;
int total = 0;
auto check = [&](const std::string& name,
const std::string& actual,
const std::string& expected) {
++total;
const bool success = actual == expected;
if (success) {
++passed;
}
std::cout << (success ? "[PASS] " : "[FAIL] ")
<< name
<< " | expected: \"" << expected
<< "\", actual: \"" << actual << "\"\n";
};
// Test 1: Empty store.
check("Empty store", store.get("foo", 1), "");
store.set("foo", "bar", 1);
// Tests 2–4: Before, at, and after the first timestamp.
check("Before first timestamp", store.get("foo", 0), "");
check("Exact first timestamp", store.get("foo", 1), "bar");
check("After first timestamp", store.get("foo", 3), "bar");
store.set("foo", "bar2", 4);
// Tests 5–7: Historical lookup and latest value.
check("Between timestamps", store.get("foo", 3), "bar");
check("Exact second timestamp", store.get("foo", 4), "bar2");
check("After latest timestamp", store.get("foo", 5), "bar2");
// Test 8: Missing key in a populated store.
check("Missing key", store.get("unknown", 5), "");
// Add another key. All set timestamps remain strictly increasing.
store.set("AAPL", "100", 6);
store.set("AAPL", "105", 10);
store.set("AAPL", "110", 15);
// Tests 9–14: Independent key and multiple historical records.
check("Second key before first update", store.get("AAPL", 5), "");
check("Second key exact first update", store.get("AAPL", 6), "100");
check("Second key between updates", store.get("AAPL", 9), "100");
check("Second key exact middle update", store.get("AAPL", 10), "105");
check("Second key before final update", store.get("AAPL", 14), "105");
check("Second key latest value", store.get("AAPL", 20), "110");
// Test 15: Updates to another key do not affect foo.
check("Keys remain independent", store.get("foo", 20), "bar2");
std::cout << "\nResult: " << passed << "/" << total
<< " tests passed.\n";
return passed == total ? 0 : 1;
}