LeetCode
快照数组
题目链接:1146. 快照数组 - 力扣(LeetCode)
题目描述
实现支持下列接口的「快照数组」- SnapshotArray:
SnapshotArray(int length)
- 初始化一个与指定长度相等的 类数组 的数据结构。初始时,每个元素都等于 0。void set(index, val)
- 会将指定索引index
处的元素设置为val
。int snap()
- 获取该数组的快照,并返回快照的编号snap_id
(快照号是调用snap()
的总次数减去1
)。int get(index, snap_id)
- 根据指定的snap_id
选择快照,并返回该快照指定索引index
的值。
示例:
输入:["SnapshotArray","set","snap","set","get"]
[[3],[0,5],[],[0,6],[0,0]]
输出:[null,null,0,null,5]
解释:
SnapshotArray snapshotArr = new SnapshotArray(3); // 初始化一个长度为 3 的快照数组
snapshotArr.set(0,5); // 令 array[0] = 5
snapshotArr.snap(); // 获取快照,返回 snap_id = 0
snapshotArr.set(0,6);
snapshotArr.get(0,0); // 获取 snap_id = 0 的快照中 array[0] 的值,返回 5
提示:
1 <= length <= 50000
- 题目最多进行
50000
次set
,snap
,和get
的调用 。 0 <= index < length
0 <= snap_id <
我们调用snap()
的总次数0 <= val <= 10^9
思路
代码
C++
class SnapshotArray {
int cur_snap_id = 0;
unordered_map<int, vector<pair<int, int>>> history; // 每个 index 的历史修改记录
public:
SnapshotArray(int) {}
void set(int index, int val) {
history[index].emplace_back(cur_snap_id, val);
}
int snap() {
return cur_snap_id++;
}
int get(int index, int snap_id) {
auto& h = history[index];
// 找快照编号 <= snap_id 的最后一次修改记录
// 等价于找快照编号 >= snap_id+1 的第一个修改记录,它的上一个就是答案
int j = ranges::lower_bound(h, make_pair(snap_id + 1, 0)) - h.begin() - 1;
return j >= 0 ? h[j].second : 0;
}
};
Java
class SnapshotArray {
private int curSnapId;
private final Map<Integer,List<int[]>> history = new HashMap<>();
public SnapshotArray(int length) {
}
public void set(int index, int val) {
history.computeIfAbsent(index, k -> new ArrayList<>()).add(new int[]{curSnapId, val});
}
public int snap() {
return curSnapId++;
}
public int get(int index, int snapId) {
if(!history.containsKey(index)){
return 0;
}
List<int[]> h = history.get(index);
int j = search(h,snapId);
return j < 0 ? 0 : h.get(j)[1];
}
private int search(List<int[]> h, int x) {
int left = -1;
int right = h.size();
while (left + 1 < right) {
int mid = left + (right - left) / 2;
if (h.get(mid)[0] <= x) {
left = mid;
} else {
right = mid;
}
}
return left;
}
}